Python函数将子进程stdout和stderr捕获到日志文件

Python函数将子进程stdout和stderr捕获到日志文件,python,bash,subprocess,io-redirection,tee,Python,Bash,Subprocess,Io Redirection,Tee,在少量的代码中会有很多事情发生。我会尽量保持简洁 我有一个python函数,它运行一个外部程序,并将stdout和stderr都转换成一个日志文件 我正在使用doctest测试函数。我需要测试输出捕获功能。下面的代码显示了我编写函数和测试的尝试。测试失败,没有写入日志文件。我不确定问题是在测试中还是在测试代码中,或者两者都有。建议 from __future__ import print_function import subprocess def run(command_line, log

在少量的代码中会有很多事情发生。我会尽量保持简洁

我有一个python函数,它运行一个外部程序,并将stdout和stderr都转换成一个日志文件

我正在使用doctest测试函数。我需要测试输出捕获功能。下面的代码显示了我编写函数和测试的尝试。测试失败,没有写入日志文件。我不确定问题是在测试中还是在测试代码中,或者两者都有。建议

from __future__ import print_function

import subprocess

def run(command_line, log_file):
    """
    # Verify stdout and stderr are both written to log file in chronological order
    >>> run("echo text to stdout; echo text to stderr 1>&2", "log")
    >>> f = open("log"); out = f.read(); f.close()
    >>> print(out.strip())
    text to stdout
    text to stderr
    """
    command_line = "set -o pipefail; " + command_line + " 2>&1 | tee " + log_file

    # Run command. Wait for command to complete. If the return code was zero then return, otherwise raise CalledProcessError
    subprocess.check_call(command_line, shell=True, executable="bash")
测试结果:

$ python -m doctest testclass.py
text to stdout
text to stderr
**********************************************************************
File "testclass.py", line 10, in testclass.run
Failed example:
    print(out.strip())
Expected:
    text to stdout
    text to stderr
Got:
    <BLANKLINE>
**********************************************************************
1 items had failures:
   1 of   3 in testclass.run
***Test Failed*** 1 failures.
$python-m doctest testclass.py
文本到标准输出
文本到标准
**********************************************************************
testclass.run中第10行的文件“testclass.py”
失败示例:
打印(out.strip())
预期:
文本到标准输出
文本到标准
得到了:
**********************************************************************
1个项目出现故障:
testclass.run中的3个中的1个
***测试失败***1次失败。

由于执行了
子流程。使用
shell=True
检查调用
,使用2个stdout/stderr重定向和
tee
并不是执行命令和捕获输出的最佳方式(实际上这是最差的方式),因此失败并不奇怪

我的解决方案是先删除
set-o pipefail
(您不需要在这里检查返回代码),然后将两个命令都用括号括起来,否则重定向/tee只适用于最后一个命令(老实说,我仍然不明白为什么您没有得到任何输出):

如果必须恢复
pipefail
功能,请在括号内执行:

command_line = "(set -o pipefail; " + command_line + ") 2>&1 | tee " + log_file

您是否尝试了由终端中的
“set-o pipefail;”+command_line+“2>&1|tee”+log_文件
生成的bash命令?输出是什么样子的?发送到终端的文本与此命令预期的一样:set-o pipefail;将文本回显到标准输出;将文本回显到标准1>&2>&1|Tlog@Jean-Françoisfafre这是一个大批量过程的一小部分,生成用户检查处理结果所需的大型日志文件。好的,我现在明白了:)是的,这就是原因。您有两个单独的命令,第一个是
将文本回送到标准输出
,您不直接将其发送,然后是
将文本回送到标准输出
,您直接(通过管道)将其发送到
t
。如果在命令序列周围放置一对括号,则会打开一个子shell,在其中执行整个命令序列。子shell本身被父shell视为一个命令,因此现在您的重定向工作与您预期的一样。我认为他根本没有得到任何输出,因为他实际上只是将
stderr
文本传输到日志文件,它可能是空的。@ThomasKühn,但他在做
向stderr 1>和
回显文本:这应该是向stderr发出文本。对,我错过了那部分。这是很难测试没有例子。嗯,现在已经解决了;)
command_line = "(set -o pipefail; " + command_line + ") 2>&1 | tee " + log_file