如何在 Python 中使用子进程重定向输出?

Posted

技术标签:

【中文标题】如何在 Python 中使用子进程重定向输出?【英文标题】:How to redirect output with subprocess in Python? 【发布时间】:2011-06-25 07:25:19 【问题描述】:

我在命令行中做了什么:

cat file1 file2 file3 > myfile

我想用python做什么:

import subprocess, shlex
my_cmd = 'cat file1 file2 file3 > myfile'
args = shlex.split(my_cmd)
subprocess.call(args) # spits the output in the window i call my python program

【问题讨论】:

在子进程中执行这样的命令不会给你任何输出。也许你想在没有 > myfile 将输出从 cat file1 file2 file3 重定向到 python 的情况下运行它? @PoltoS 我想加入一些文件,然后处理生成的文件。我认为使用 cat 是最简单的选择。有没有更好的/pythonic 方式来做到这一点? os.sendfile()-based 解决方案是可能的,请参阅Reproduce the unix cat command in python 我认为输出重定向('>' 或 '>>')在 subprocess.Popen 中不起作用(至少在 Python 2.7 中)(在 shell=True 模式下)在这个例子中,如其他人指出,您可以通过不使用重定向来解决此问题,但在其他情况下,重定向很有用。如果 subprocess.Popen 不支持重定向或管道,则应记录(和/或 os.system() 在修复之前不应弃用) 【参考方案1】:

Python 3.5+ 中重定向输出,只需将 stdout 参数的打开文件句柄传递给 subprocess.run

# Use a list of args instead of a string
input_files = ['file1', 'file2', 'file3']
my_cmd = ['cat'] + input_files
with open('myfile', "w") as outfile:
    subprocess.run(my_cmd, stdout=outfile)

正如其他人所指出的,为此目的使用像 cat 这样的外部命令是完全无关的。

【讨论】:

这应该是从 Python 使用 shell 时管道一般问题的答案 这是正确答案,不是标记为正确的答案。 对于 Python 3.5+ 使用 subprocess.run(my_cmd, stdout=outfile) 替换 subprocess.call(...) 请注意,这不适用于自定义文件对象,如果它们没有 fileno 字段(如果它们不是真实文件)。 由于 Python 【参考方案2】:

更新:不鼓励使用 os.system,尽管它在 Python 3 中仍然可用。


使用os.system:

os.system(my_cmd)

如果你真的想使用子流程,这里是解决方案(大部分来自子流程的文档):

p = subprocess.Popen(my_cmd, shell=True)
os.waitpid(p.pid, 0)

OTOH,您可以完全避免系统调用:

import shutil

with open('myfile', 'w') as outfile:
    for infile in ('file1', 'file2', 'file3'):
        shutil.copyfileobj(open(infile), outfile)

【讨论】:

它有效,但是让我问你:如果 os.system 已经完成了工作,那么子进程库的意义何在?我觉得我应该一直使用 subprocess ,因为它是一个专门用于此任务的库,尽管因为我只是为自己做这件事,所以这次使用 os.system 会很好。 子流程库比os.system灵活得多,可以精确建模os.system,但使用起来也更复杂。 os.systemsubprocess 之前。前者是后者打算替换的遗留 API。 @catatemypythoncode:您不应该使用os.system()shell=True。要重定向子进程的输出,请使用stdout 参数,如Ryan Thompson's answer 所示。尽管您不需要子进程 (cat),但您可以使用纯 Python 连接文件。 OTOH = 另一方面【参考方案3】:

@PoltoS 我想加入一些文件,然后处理生成的文件。我认为使用 cat 是最简单的选择。有没有更好的/pythonic 方式来做到这一点?

当然:

with open('myfile', 'w') as outfile:
    for infilename in ['file1', 'file2', 'file3']:
        with open(infilename) as infile:
            outfile.write(infile.read())

【讨论】:

【参考方案4】:

一个有趣的案例是通过将类似文件附加到文件来更新文件。这样就不必在此过程中创建新文件。在需要附加大文件的情况下特别有用。这是直接从 python 使用终端命令行的一种可能性。

import subprocess32 as sub

with open("A.csv","a") as f:
    f.flush()
    sub.Popen(["cat","temp.csv"],stdout=f)

【讨论】:

【参考方案5】:
size = 'ffprobe -v error -show_entries format=size -of default=noprint_wrappers=1:nokey=1 dump.mp4 > file'
proc = subprocess.Popen(shlex.split(size), shell=True)
time.sleep(1)
proc.terminate() #proc.kill() modify it by a suggestion
size = ""
with open('file', 'r') as infile:
    for line in infile.readlines():
        size += line.strip()

print(size)
os.remove('file')

当你使用subprocess时,必须杀死进程。这是一个例子。如果你不杀死进程,file将为空,你可以阅读什么都没有。它可以在 Windows 上运行。我无法确保它可以在 Unix 上运行。

【讨论】:

这是一个糟糕的代码示例(它在 Unix 上不起作用;它展示了不良做法 for line in .readlines():s +=)和 proc.kill() 通常可能导致信息丢失(它不会' t 允许子进程正常终止(在 Unix 上)——未刷新的内容丢失)。无论如何,关于缓冲的注释更适合作为注释。 我在 Windows 上运行它是可以的(因为在 Windows 上 kill 等于终止)。在 Unix 上,您可能应该使用 proc.terminate()。 @J.F. Sebastian 我的电脑上没有 Unix 系统。 如果您在 Windows 上,则删除shlex.split()、删除shell=True、删除>file、删除open() 等并使用stdout=PIPETimer(1, proc.terminate).start()output = proc.communicate()[0] 代替。这是complete example。更多解决方案:Stop reading process output in Python without hang? 注意:问题中没有要求您需要手动终止子进程——您可以解决其他问题,例如,如果一个进程的 stdout 是 tty 但它是题外话,它的行为可能会有所不同.

以上是关于如何在 Python 中使用子进程重定向输出?的主要内容,如果未能解决你的问题,请参考以下文章

重定向子进程标准输出

获取 node.js 中所有嵌套子进程的标准输出

IPC - 如何将命令输出重定向到子进程中的共享内存段

将子进程的标准输出重定向到 2 个或更多子进程的标准输入

Windows:具有重定向输入和输出的子进程

在C中重定向子进程的文件输出