读取文件时执行SSH命令导致read循环提前终止的问题
SSH命令干扰bash read循环终止的原因及解决办法
问题场景
你编写了一个用于从CSV读取配置并执行rsync备份的bash脚本:
#!/bin/bash while IFS="," read -r share source type subdir rsyncPath do # 运行共享目录的预检查脚本 [ -f "$share.preflight" ] && $share.preflight # 执行rsync备份命令 done < <(grep -P -v '^\s*#' "inputfile")
对应的inputfile内容示例:
Info,user@remotehost:/share,,,/usr/bin/sudo /opt/bin/rsync docker,user@remotehost:/share,,,/usr/bin/sudo /opt/bin/rsync
同时存在两个预检查脚本:docker.preflight:
#!/bin/bash ssh user@remotehost 'echo Stopping docker service'
Info.preflight:
#!/bin/bash echo "Hello Info.preflight"
遇到的问题:当Info行在inputfile中位于docker行之前时,脚本可正常读取两行并执行对应预检查;但将docker行调整到第一行时,执行完docker.preflight后,read循环直接终止,不再读取后续内容。
原因分析
核心问题在于SSH默认会读取当前进程的标准输入(stdin):
- 你的
while read循环是通过进程替换<(grep ...)获取输入,这个输入流会成为整个循环体的stdin。 - 当执行
docker.preflight里的ssh命令时,SSH会直接读取当前的stdin(也就是inputfile中剩余的行内容),导致后续的read命令再也获取不到输入,循环直接终止。
而Info.preflight里只有echo命令,不会读取stdin,所以当它在第一行时,不会抢占循环的输入流,read能正常读取后续的docker行。
解决办法
有两种可靠的解决方式:
1. 给SSH命令添加-n参数
修改docker.preflight中的SSH命令,加上-n参数将其stdin重定向到/dev/null,避免它读取循环的输入流:
#!/bin/bash ssh -n user@remotehost 'echo Stopping docker service'
-n参数是SSH的标准参数,专门用于防止SSH从stdin读取数据,适合这种场景。
2. 执行预检查脚本时重定向其stdin
在主脚本中执行预检查脚本时,强制将其stdin重定向到/dev/null,不管脚本内部有没有读取stdin的命令,都不会影响循环的输入:
#!/bin/bash while IFS="," read -r share source type subdir rsyncPath do # 运行共享目录的预检查脚本,重定向stdin避免干扰 [ -f "$share.preflight" ] && "$share.preflight" < /dev/null # 执行rsync备份命令 done < <(grep -P -v '^\s*#' "inputfile")
这种方式更通用,即使后续预检查脚本新增了其他读取stdin的命令,也不会影响循环。
内容的提问来源于stack exchange,提问作者Joern Doe
相关产品推荐
相关产品推荐

