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

读取文件时执行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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 05:25:39