如何使用Python sh模块合并捕获stdout与stderr输出?
用Python sh模块实现终端式的stdout/stderr输出与捕获
嘿,这个需求我刚好折腾过!用sh模块要做到和终端完全一致的输出效果(保留stdout和stderr的原有顺序,同时还能捕获合并后的内容),其实有几个靠谱的路子,我给你逐个拆解:
1. 只需要终端式输出,不需要捕获内容
这是最简单的情况——sh模块默认就会把命令的stdout和stderr直接转发到当前进程的对应流,和你在终端敲命令的效果一模一样:
import sh # 运行这条命令,你会看到和终端里敲`ls -l /nonexistent`完全一样的输出 sh.ls("-l", "/nonexistent")
不管命令成功还是失败,输出顺序、内容都和终端完全一致,不需要额外配置。
2. 实时输出+捕获合并后的内容
如果既要让输出实时显示(和终端同步),又要把所有输出内容保存下来,那可以写个简单的流处理类来接管输出:
import sys import sh class StreamLogger: def __init__(self): self.captured = [] def write(self, data): # 实时把内容输出到终端 sys.stdout.write(data) sys.stdout.flush() # 同时把内容存到缓冲区 self.captured.append(data) def get_combined_output(self): return ''.join(self.captured) # 初始化日志器 logger = StreamLogger() try: # 把命令的stdout和stderr都定向到我们的日志器 sh.ls("-l", "/nonexistent", _out=logger, _err=logger) except sh.ErrorReturnCode: # 命令出错也没关系,我们已经捕获了所有输出 pass # 事后可以拿到合并后的完整输出 print("\n--- 捕获到的所有输出 ---") print(logger.get_combined_output())
这个方法的优势是完全复刻终端的输出时序,不会出现stdout和stderr乱序的问题,同时还能完整保存所有内容。
3. 只需要捕获合并内容,不需要实时输出
如果不需要实时看到输出,只是想事后拿到合并后的stdout和stderr,可以用sh内置的_err_to_out=True参数,它会把stderr重定向到stdout,这样就能一次性捕获所有内容:
import sh try: # _err_to_out=True 把stderr合并到stdout,_out=str 让sh返回stdout的字符串内容 result = sh.ls("-l", "/nonexistent", _err_to_out=True, _out=str) except sh.ErrorReturnCode as e: # 命令执行失败时,错误信息会存在e.stdout里 combined_output = e.stdout else: # 命令成功时,结果在result里 combined_output = result print("合并后的输出:") print(combined_output)
这个方式相当于终端里的command 2>&1,输出顺序和终端完全一致,代码也最简洁。
小提示
- 如果你用的是sh的
Command对象(比如sh.Command("ls")),上述所有参数同样适用。 - 要注意命令执行失败时会抛出
ErrorReturnCode异常,记得用try-except捕获,避免程序崩溃。
内容的提问来源于stack exchange,提问作者Edward Ned Harvey
相关产品推荐
相关产品推荐

