You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:将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

关键细节说明

  1. 变量区分:
    • 本地变量(如$LOCAL_SERVICE)直接写在heredoc里,因为分界符EOF没有加引号,本地Bash会先展开这些变量再传给远程
    • 远程变量(如$id)前面加\转义,确保本地Bash不会解析它,留到远程Shell执行时处理
  2. 可读性优化:
    • 把长命令拆成多行,docker run的每个参数单独一行,用\连接换行
    • 给远程命令加缩进,逻辑结构一目了然
  3. 安全规范:
    • 给变量加双引号(如"\$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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:21:50