如何在 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.system
在 subprocess
之前。前者是后者打算替换的遗留 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=PIPE
、Timer(1, proc.terminate).start()
; output = proc.communicate()[0]
代替。这是complete example。更多解决方案:Stop reading process output in Python without hang? 注意:问题中没有要求您需要手动终止子进程——您可以解决其他问题,例如,如果一个进程的 stdout 是 tty 但它是题外话,它的行为可能会有所不同.以上是关于如何在 Python 中使用子进程重定向输出?的主要内容,如果未能解决你的问题,请参考以下文章