SSH远程执行for循环异常:循环在源服务器运行而非目标服务器
解决SSH远程执行循环时本地展开命令/变量的问题
问题分析
你遇到的核心问题是:使用<< EOT的here-doc时,bash默认会在本地服务器展开所有的命令替换(如cat file.txt)和变量引用(如${appName}),导致循环逻辑在本地执行,而非目标服务器。即使把file.txt放到本地,变量也会被本地提前替换,无法传递到远程循环中。
解决方案
根据file.txt的存放位置,提供两种可行方案:
场景1:file.txt在目标服务器上
通过给here-doc分界符添加单引号(<< 'EOT'),禁止本地的命令/变量展开,让所有代码在目标服务器执行。同时改用sudo -u user1直接执行命令,避免sudo su - user1切换shell导致后续命令失效的问题:
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /app/.ssh/key.pem -t abc@$server1 << 'EOT' sudo -u user1 bash -c ' cd /app/dir1 # 用$(cat)替代反引号,更规范且避免嵌套问题 for appName in $(cat file.txt) do mv /app/dir1/httpd/${appName}/ /app/dir1/backup/${appName}/ cp -R /app/dir2/source/${appName}/ /app/dir1/httpd/${appName} done ' EOT
场景2:file.txt在本地服务器上
将本地file.txt的内容传递到目标服务器,用while read循环处理(比for更可靠,能处理带空格的文件名):
# 本地读取文件内容,通过管道传递给远程服务器 cat file.txt | ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i /app/.ssh/key.pem -t abc@$server1 ' sudo -u user1 bash -c " cd /app/dir1 while read -r appName do # 转义变量避免本地提前展开 mv /app/dir1/httpd/\${appName}/ /app/dir1/backup/\${appName}/ cp -R /app/dir2/source/\${appName}/ /app/dir1/httpd/\${appName} done " '
关键注意事项
- 优先使用
$(命令)替代反引号`命令`,前者语法更清晰,支持嵌套。 - 避免使用
sudo su - user1切换shell,改用sudo -u user1 bash -c '命令'直接以目标用户身份执行脚本逻辑,避免shell切换导致的命令中断。 - 当需要远程执行包含变量/命令的脚本时,务必通过单引号包裹或转义,防止本地提前展开。
内容的提问来源于stack exchange,提问作者vow7779
相关产品推荐
相关产品推荐

