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

Bash下scp命令输出来源及捕获输出到变量/数组方法

问题1:scp进度文本的来源
  • 你看到的传输进度100%是本地scp客户端生成输出的,和远程端无关:远程服务器上的sshd进程只负责传文件数据和协议控制报文,根本不会返回进度类文本,传输百分比、速率、剩余时间全是本地客户端统计已传数据量后自己算出来的。
  • 常规重定向抓不到这部分内容的核心原因:scp只要检测到自己跑在真实终端(TTY)里,就不会把进度写到标准输出(fd1)、标准错误(fd2)这两个常规流里,而是直接打开进程绑定的/dev/tty设备文件往里面写进度,这部分输出直接绕过了普通的流重定向逻辑,这就是你写了重定向规则之后进度照样打在终端上、变量却空着的根本原因。
  • 顺带说下你原代码的重定向写法错误:shell解析重定向是从左往右执行的,你写的2>&1 > $mytty实际效果是:先把标准错误接到命令替换的管道(也就是本来要存到myvar的通道),再把标准输出切到TTY,这时候标准错误还连在管道上,但scp的进度根本不走标准错误,管道里读不到任何东西,myvar自然是空的。就算你把重定向顺序写对成> $mytty 2>&1,还是抓不到进度——毕竟进度压根不经过这两个文件描述符。
问题2:Bash中捕获scp进度输出的正确方法

scp只有在检测到自己运行在终端环境下才会输出进度条,要抓到这部分直接写TTY的内容,得用伪终端(PTY)伪造真实终端环境跑scp,再把所有终端输出截下来,最方便的是用系统默认预装的script命令实现:

捕获到普通变量

#!/bin/bash
# 参数说明:
# -q 静默模式,不打印script自身的启动、退出提示
# -c 后面接要执行的scp命令
# 末尾指定记录文件为/dev/null,伪终端里的所有输出会走到script的标准流,可供捕获
myvar=$(script -q -c "scp test.js crashdog@webserver.com:/home/crashdog" /dev/null 2>&1)

echo "捕获到的scp输出:"
echo "$myvar"

捕获到数组

如果需要按行拆分存到数组,配合mapfile和进程替换就行:

#!/bin/bash
# 把scp的所有终端输出按行读入scp_output数组
mapfile -t scp_output < <(script -q -c "scp test.js crashdog@webserver.com:/home/crashdog" /dev/null 2>&1)

# 遍历输出数组内容
echo "数组存储的输出行:"
for line_idx in "${!scp_output[@]}"; do
    echo "行$((line_idx+1)): ${scp_output[$line_idx]}"
done

补充:如果遇到极个别没有预装script的环境,也可以用expect的spawn创建伪终端运行scp再抓输出,但绝大多数Linux发行版、macOS都默认带script,优先用这个方案最省事。

内容的提问来源于stack exchange,提问作者crashdog

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:09:14