Python:subprocess.call,stdout to file,stderr to file,实时在屏幕上显示stderr

时间:2013-08-20 21:03:23

标签: python subprocess stderr

我有一个命令行工具(实际上是几个),我正在用Python编写包装器。

该工具通常使用如下:

 $ path_to_tool -option1 -option2 > file_out

用户将输出写入file_out,并且还可以在工具运行时查看该工具的各种状态消息。

我想复制此行为,同时还将stderr(状态消息)记录到文件中。

我拥有的是:

from subprocess import call
call(['path_to_tool','-option1','option2'], stdout = file_out, stderr = log_file)

这很好用,除了stderr没有写入屏幕。 我当然可以添加代码来将log_file的内容打印到屏幕上,但是用户将在完成所有操作后看到它,而不是在它发生时。

总结一下,期望的行为是:

  1. 使用call()或subprocess()
  2. 将stdout直接发送到文件
  3. 将stderr直接发送到文件,同时还将stderr实时写入屏幕,就好像是 工具直接从命令行调用。
  4. 我有一种感觉,我要么缺少一些非常简单的东西,要么这比我想象的要复杂得多...感谢您的帮助!

    编辑:这只需要在Linux上运行。

2 个答案:

答案 0 :(得分:1)

我认为你所寻找的是:

import sys, subprocess
p = subprocess.Popen(cmdline,
                     stdout=sys.stdout,
                     stderr=sys.stderr)

要将输出/日志写入文件,我会修改我的cmdline以包含常用的重定向,就像在普通的linux bash / shell上完成一样。例如,我会将tee附加到命令行:cmdline += ' | tee -a logfile.txt'

希望有所帮助。

答案 1 :(得分:1)

我必须对@ abarnert对Python 3的回答进行一些更改。这似乎有效:

def tee_pipe(pipe, f1, f2):
    for line in pipe:
        f1.write(line)
        f2.write(line)

proc = subprocess.Popen(["/bin/echo", "hello"],
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)

# Open the output files for stdout/err in unbuffered mode.
out_file = open("stderr.log", "wb", 0)
err_file = open("stdout.log", "wb", 0)

stdout = sys.stdout
stderr = sys.stderr

# On Python3 these are wrapped with BufferedTextIO objects that we don't
# want.
if sys.version_info[0] >= 3:
    stdout = stdout.buffer
    stderr = stderr.buffer

# Start threads to duplicate the pipes.
out_thread = threading.Thread(target=tee_pipe,
                              args=(proc.stdout, out_file, stdout))
err_thread = threading.Thread(target=tee_pipe,
                              args=(proc.stderr, err_file, stderr))

out_thread.start()
err_thread.start()

# Wait for the command to finish.
proc.wait()

# Join the pipe threads.
out_thread.join()
err_thread.join()