subprocess.Popen无法捕获scp的stdout输出,如何实时获取传输进度?
解决subprocess实时捕获scp原始进度输出的问题
核心原因
scp的进度输出默认走标准错误流(stderr),但通过subprocess.PIPE捕获时,系统会对stderr做全缓冲,导致无法实时拿到输出。直接运行脚本时控制台能实时显示,是因为终端环境下stderr默认是行缓冲模式。
解决方法
方法1:强制scp使用行缓冲输出
修改minscp.sh里的scp命令,用stdbuf强制行缓冲,同时关闭冗余日志:
stdbuf -o L -e L scp -q /本地move文件夹路径/* 远程用户@远程地址:/目标路径/
-o L:设置stdout为行缓冲-e L:设置stderr为行缓冲-q:屏蔽scp的非进度冗余输出,只保留原始进度行
方法2:Python端配置实时读取逻辑
调用脚本时,设置子进程为行缓冲模式,循环读取stderr内容:
import subprocess # 调用目标脚本 proc = subprocess.Popen( ["./minscp.sh"], stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, bufsize=1, # 启用行缓冲 universal_newlines=True ) # 实时读取并处理进度输出 for line in iter(proc.stderr.readline, ''): print(line.strip()) # 替换为你的业务处理逻辑 proc.wait()
方法3:重定向scp输出到stdout(可选)
在minscp.sh中将stderr重定向到stdout,后续读取stdout即可:
scp /本地move文件夹路径/* 远程用户@远程地址:/目标路径/ 2>&1
然后Python代码读取stdout,结合行缓冲设置,同样能实时获取进度。
关键注意点
- 不要用
scp -v,它会输出大量调试日志,干扰原始进度行捕获 - 必须确保子进程输出为行缓冲,否则会等到缓冲满才一次性输出
- 循环读取时用
iter(proc.stderr.readline, ''),避免阻塞等待
内容的提问来源于stack exchange,提问作者alpastor
相关产品推荐
相关产品推荐

