GitHub Actions中PowerShell的SSH+MongoDB命令转义语法问题排查
问题排查:GitHub Actions PowerShell Runner中SSH+Docker命令组合语法错误
已知正常场景
Windows PowerShell单独执行SSH命令:可正常连接到Linux主机dbhost的ksh shell
PS C:\Users\sshuser_App\Downloads> ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q -t -i C:\Users\sshuser\.ssh\id_rsa_tmp sshuser@dbhostLinux主机ksh中单独执行Docker命令:可正常运行
sudo docker exec -ti mongodockerimage mongo --port 27062 --authenticationDatabase '$external' --authenticationMechanism PLAIN -u 'mydbuser' -p 'mydbpass' --eval "db = db.getSiblingDB('testdb'); print(db.getName()); load('audit/masking_scripts/1mask.txt')"Linux Runner的bash中组合命令:可正常执行
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q -t -i C:\Users\sshuser\.ssh\id_rsa_tmp sshuser@dbhost "sudo docker exec -ti mongodockerimage mongo --port 27062 --authenticationDatabase '\$external' --authenticationMechanism PLAIN -u 'mydbuser' -p 'mydbpass' --eval \"db = db.getSiblingDB('testdb'); print(db.getName()); load('audit/masking_scripts/1mask.txt')\""
出错场景
在GitHub Actions的PowerShell Runner中组合命令时,尝试用反引号转义$和双引号后,出现语法错误:
PS C:\Users\sshuser_App\Downloads> ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -q -t -i C:\Users\sshuser\.ssh\id_rsa_tmp sshuser@dbhost "sudo docker exec -ti mongodockerimage mongo --port 27062 --authenticationDatabase '$external' --authenticationMechanism PLAIN -u 'mydbuser' -p 'mydbpass' --eval `"db = db.getSiblingDB('testdb'); print(db.getName()); load('audit/masking_scripts/1mask.txt')`"" ksh: syntax error at line 1: `(' unexpected
期望参数化格式
run: | ${{ inputs.executesshstring }}@${{ inputs.targethost }} "sudo docker exec ${{ inputs.dockerImage }} mongo --port ${{ inputs.DBport }} --authenticationDatabase '`$external' --authenticationMechanism PLAIN -u ${{ inputs.DBuser }} -p ${{ inputs.DBpass }} --eval `"db = db.getSiblingDB('${{ inputs.DBname }}'); print(db.getName()); load('audit/masking_scripts/${{ inputs.executefilename }}')`""
问题原因与解决方案
核心问题
PowerShell的引号解析规则与ksh存在冲突:
- 用双引号包裹远程命令时,PowerShell会优先解析
$external作为本地变量,导致传到ksh时该变量被替换为空,破坏了--authenticationDatabase '$external'的语法。 - 双引号的转义在PowerShell和ksh之间叠加,导致最终传到ksh的命令语法混乱。
修正方案
改用单引号包裹整个远程SSH命令,同时在PowerShell中用'\''转义远程命令中的单引号,避免PowerShell解析内部变量,同时保证ksh能正确识别引号:
修正后的参数化命令
run: | ${{ inputs.executesshstring }}@${{ inputs.targethost }} 'sudo docker exec ${{ inputs.dockerImage }} mongo --port ${{ inputs.DBport }} --authenticationDatabase '\''$external'\'' --authenticationMechanism PLAIN -u '\''${{ inputs.DBuser }}'\'' -p '\''${{ inputs.DBpass }}'\'' --eval "db = db.getSiblingDB('\''${{ inputs.DBname }}'\''); print(db.getName()); load('\''audit/masking_scripts/${{ inputs.executefilename }}'\'')"'
修正逻辑说明
- 单引号包裹整个远程命令:PowerShell不会解析单引号内部的
$符号和变量,直接将完整内容传递给ksh。 '\'':PowerShell中在单引号字符串内表示单引号的写法,最终传到ksh时会被解析为单个单引号,保证命令中用户、密码、数据库名等字符串的正确包裹。--eval后的双引号直接保留:ksh可以正确解析双引号内的MongoDB脚本逻辑,无需额外转义。
内容的提问来源于stack exchange,提问作者Ashar
相关产品推荐
相关产品推荐

