使用subprocess调用带重定向的Bash脚本时的输出异常问题
问题与解决方案
原Bash脚本
#!/bin/bash BIN_FOLDER=bin SEQ_BIN=some_binary PROFILE_FOLDER=profiles/ FILENAME=$1 mkdir -p $PROFILE_FOLDER sudo perf record -g -F 999 $BIN_FOLDER/$SEQ_BIN "${@:2}" sudo sh -c "perf script -F +pid > $PROFILE_FOLDER/$FILENAME.perf" sudo rm perf.*
直接运行脚本的预期输出
<some_binary output> [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0,025 MB perf.data (6 samples) ]
问题描述
直接在Shell中运行上述脚本时,终端能正常输出预期内容,同时生成profiles/$FILENAME.perf文件。但通过Python的subprocess.run并设置capture_output=True调用时,捕获到的stdout结果变成了perf script命令的输出(呈现为大量乱码),无法得到和直接运行时一致的终端内容。需要在保留脚本生成文件功能的前提下解决捕获输出的问题,且最好不修改原Bash脚本。
解决方案
方法1:合并stdout与stderr,捕获终端完整输出
直接运行脚本时,终端会同时显示some_binary的标准输出(stdout)和perf record的提示信息(标准错误stderr),而perf script的输出已被脚本内的重定向写入文件,不会出现在终端。在Python中,只需将脚本的stderr合并到stdout中捕获,就能得到和终端完全一致的内容:
import subprocess # 替换为你的脚本路径、输出文件名及参数 cmd = ["./your_script.sh", "test_profile", "arg1", "arg2"] result = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) # 打印捕获到的内容,与直接运行脚本的终端输出一致 print(result.stdout) # 脚本会正常生成profiles/test_profile.perf文件
方法2:单独捕获stdout和stderr,按需处理
如果需要分开处理some_binary的输出和perf record的提示信息,可以分别捕获两个流:
import subprocess cmd = ["./your_script.sh", "test_profile", "arg1", "arg2"] result = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) # some_binary的输出内容 print("程序输出:", result.stdout) # perf record的提示信息 print("perf记录日志:", result.stderr)
注意事项
如果脚本依赖特定工作目录才能正确生成文件,可以在调用时指定cwd参数:
result = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, cwd="/path/to/script/directory" # 脚本所在目录 )
内容的提问来源于stack exchange,提问作者Diogo Almeida
相关产品推荐
相关产品推荐

