求助:将SSH远程执行命令改写为多行Bash脚本失败
解决SSH远程执行多行Docker命令的问题
我太懂你折腾两小时的憋屈了——把一行冗长的SSH远程命令拆成多行,光是引号嵌套和变量展开的坑就能绕晕人,更别说还要区分本地和远程变量了。咱们一步步来解决这个问题:
核心问题拆解
你的需求里有两个关键点:
- 本地变量:
$1(服务/镜像名)和$2(远程主机地址)需要在本地脚本执行时就展开 - 远程变量:
$id是远程主机上生成的,必须交给远程Shell去解析
原命令的问题在于用单引号包裹了整个远程命令,导致里面的$1会被远程Shell当成它自己的位置参数,而不是你本地脚本传入的参数,这肯定会出错。
改写后的多行可读版本
用Bash的Here Document( heredoc)可以完美解决多行命令的可读性问题,同时清晰区分本地和远程变量:
echo "Deploying $1 to remote" # 先把本地参数存成更清晰的变量,避免混淆 LOCAL_SERVICE="$1" REMOTE_HOST="$2" # 用heredoc传递多行远程命令 sudo ssh -i ../keys/key.pem username@$REMOTE_HOST << EOF # 远程变量$id前面加反斜杠,让本地Bash不解析它 id=\$(docker ps -a -q -f name=$LOCAL_SERVICE) if [ -n "\$id" ]; then docker rm --force "\$id" fi # docker run参数拆成多行,用反斜杠换行,更易读 docker run -d --network host \ -v /var/log/$LOCAL_SERVICE/:/var/log/$LOCAL_SERVICE/ \ -e SERVER_PORT=80 \ --name $LOCAL_SERVICE \ username/image:$LOCAL_SERVICE EOF
关键细节说明
- 变量区分:
- 本地变量(如
$LOCAL_SERVICE)直接写在heredoc里,因为分界符EOF没有加引号,本地Bash会先展开这些变量再传给远程 - 远程变量(如
$id)前面加\转义,确保本地Bash不会解析它,留到远程Shell执行时处理
- 本地变量(如
- 可读性优化:
- 把长命令拆成多行,docker run的每个参数单独一行,用
\连接换行 - 给远程命令加缩进,逻辑结构一目了然
- 把长命令拆成多行,docker run的每个参数单独一行,用
- 安全规范:
- 给变量加双引号(如
"\$id"、"$LOCAL_SERVICE"),避免遇到空格、特殊字符时出现意外错误
- 给变量加双引号(如
另一种简化写法(不用heredoc)
如果不想用heredoc,也可以把远程命令用双引号包裹,同时转义远程变量:
echo "Deploying $1 to remote" sudo ssh -i ../keys/key.pem username@$2 " id=\$(docker ps -a -q -f name=$1) if [ -n \"\$id\" ]; then docker rm --force \"\$id\" fi docker run -d --network host \ -v /var/log/$1/:/var/log/$1/ \ -e SERVER_PORT=80 \ --name $1 \ username/image:$1 "
这种写法的核心是用双引号包裹远程命令,让本地变量$1、$2正常展开,同时用\转义远程的$id和内部的双引号。不过heredoc的可读性还是更好一些。
内容的提问来源于stack exchange,提问作者B.Gen.Jack.O.Neill
相关产品推荐
相关产品推荐

