子shell脚本运行scp不显示传输文件列表的原因及规避方案
问题原因
scp的默认输出逻辑会检测自身标准输出(stdout)是否绑定到交互式终端(TTY):
- 直接在交互式shell运行脚本时,scp的stdout指向终端,会正常输出每个传输的文件列表
- 当你通过
$()命令替换、管道将my_script的stdout接入tee时,scp的stdout直接连接的是管道而非终端,scp检测到非交互输出环境后,会默认关闭传输文件列表的输出,避免管道处理场景下的日志干扰。
注意:即使你通过tee将输出重定向到绑定终端的/dev/fd/5,scp只会检测自身第一层stdout的连接对象,不会识别最终输出终点,因此仍然不会输出列表
规避方案(无需使用
scp -v) - 方案1:使用
unbuffer工具(属于expect软件包)为scp分配伪终端,模拟交互环境,修改my_script中的scp命令为:
unbuffer scp -- 'somehost:*.txt' dest_dir
该方案会欺骗scp判定自身运行在交互终端下,正常输出传输文件列表。
- 方案2:使用
script命令模拟终端环境运行my_script,无需修改原my_script的内容,将第二个脚本的捕获逻辑修改为:
exec 5>&1 foo=$(script -q -c my_script /dev/null | tee /dev/fd/5) || exit -1
script命令默认会为执行的命令创建伪终端,同样可以触发scp的交互模式输出。
- 方案3:如果你不需要将scp的传输列表存入变量
foo,仅需要打印到终端,可以将scp的输出重定向到标准错误(stderr),修改my_script的scp命令为:
scp -- 'somehost:*.txt' dest_dir >&2
命令替换$()默认仅捕获标准输出,scp输出到stderr后会直接打印到终端,不会被管道捕获。
内容的提问来源于stack exchange,提问作者einpoklum
相关产品推荐
相关产品推荐

