使用SSH执行命令导致Bash Shell脚本循环终止问题求助
解决SSH循环仅执行一次的问题
嘿,这个坑我之前也踩过!问题的核心其实很简单:SSH会默认读取标准输入(stdin),而你用来驱动循环的file-name正好是通过stdin传给while read的。当第一次循环里的SSH命令执行时,它会把文件里剩下的所有内容都当作自己的输入给“吞”掉,导致read命令再也读不到下一行,循环直接终止——这就是为什么替换成打印操作就正常,一用SSH就只跑一次。
下面给你几个靠谱的修复方案,按需选就行:
方案1:给SSH加-n参数(最简便)
ssh -n会强制SSH从/dev/null读取标准输入,彻底切断它和循环输入的关联。修改后的脚本大概是这样:
while read line; do # 加个-n参数,让SSH别抢循环的输入 ssh -n your-user@remote-host "ls" done < file-name
这个方法最直接,几乎不需要改脚本结构,适合大多数场景。
方案2:用额外的文件描述符读取文件
把文件绑定到非0号的文件描述符(比如3),让read从这个专属FD读取内容,这样SSH就碰不到循环的输入源了:
# 把file-name绑定到3号文件描述符 while read -u 3 line; do ssh your-user@remote-host "ls" done 3< file-name
这个方案更灵活,如果你后续循环里还有其他需要用stdin的操作,也不会互相干扰。
方案3:手动重定向SSH的stdin到/dev/null
和方案1原理一样,只是手动把SSH的输入指向空设备,写法上稍微不同:
while read line; do ssh your-user@remote-host "ls" < /dev/null done < file-name
效果和-n完全一致,看你个人习惯选哪种。
验证小技巧
你可以在循环里加一行打印,确认所有行都被处理了:
while read line; do echo "正在处理行内容:$line" ssh -n your-user@remote-host "ls" done < file-name
如果所有行的打印都出来,同时远程主机上执行了N次ls,就说明修复成功啦!
内容的提问来源于stack exchange,提问作者Bryant
相关产品推荐
相关产品推荐

