def*_*ode 216 python subprocess
我的python脚本使用subprocess来调用非常嘈杂的linux实用程序.我想将所有输出存储到日志文件中并向用户显示一些输出.我认为以下内容可行,但在实用程序产生大量输出之前,输出不会显示在我的应用程序中.
#fake_utility.py, just generates lots of output over time
import time
i = 0
while True:
print hex(i)*512
i += 1
time.sleep(0.5)
#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
for line in proc.stdout:
#the real code does filtering here
print "test:", line.rstrip()
Run Code Online (Sandbox Code Playgroud)
我真正想要的行为是过滤器脚本在从子进程接收时打印每一行.Sorta就像tee使用python代码一样.
我错过了什么?这甚至可能吗?
更新:
如果将a sys.stdout.flush()添加到fake_utility.py,则代码在python 3.1中具有所需的行为.我正在使用python 2.6.您会认为使用proc.stdout.xreadlines()将与py3k一样工作,但事实并非如此.
更新2:
这是最小的工作代码.
#fake_utility.py, just generates lots of output over time
import sys, time
for i in range(10):
print i
sys.stdout.flush()
time.sleep(0.5)
#display out put line by line
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
#works in python 3.0+
#for line in proc.stdout:
for line in iter(proc.stdout.readline,''):
print line.rstrip()
Run Code Online (Sandbox Code Playgroud)
Rôm*_*con 168
自从我上次使用Python以来已经很长时间了,但我认为问题在于语句for line in proc.stdout,它在迭代之前读取整个输入.解决方案是使用readline():
#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
while True:
line = proc.stdout.readline()
if not line:
break
#the real code does filtering here
print "test:", line.rstrip()
Run Code Online (Sandbox Code Playgroud)
当然,你仍然需要处理子进程的缓冲.
注意:根据文档,使用迭代器的解决方案应该等效于使用readline(),除了预读缓冲区,但(或者正因为如此)建议的更改确实为我产生了不同的结果(Windows XP上的Python 2.5).
jbg*_*jbg 37
派对迟到了,但很惊讶没有看到我认为这里最简单的解决方案:
import io
import subprocess
proc = subprocess.Popen(["prog", "arg"], stdout=subprocess.PIPE)
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): # or another encoding
# do something with line
Run Code Online (Sandbox Code Playgroud)
Ste*_*ter 17
实际上,如果您整理了迭代器,那么缓冲现在可能是您的问题.您可以告诉子进程中的python不要缓冲其输出.
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
Run Code Online (Sandbox Code Playgroud)
变
proc = subprocess.Popen(['python','-u', 'fake_utility.py'],stdout=subprocess.PIPE)
Run Code Online (Sandbox Code Playgroud)
从python中调用python时我需要这个.
use*_*134 14
您想要将这些额外参数传递给subprocess.Popen:
bufsize=1, universal_newlines=True
Run Code Online (Sandbox Code Playgroud)
然后你可以像你的例子一样迭代.(使用Python 3.5测试)
Rot*_*eti 10
一个允许实时、逐行迭代stdout和stderr同时迭代的函数
如果你需要得到输出流两种stdout,并stderr在同一时间,你可以使用下面的函数。
该函数使用队列将两个 Popen 管道合并为一个迭代器。
在这里我们创建函数read_popen_pipes():
from queue import Queue, Empty
from concurrent.futures import ThreadPoolExecutor
def enqueue_output(file, queue):
for line in iter(file.readline, ''):
queue.put(line)
file.close()
def read_popen_pipes(p):
with ThreadPoolExecutor(2) as pool:
q_stdout, q_stderr = Queue(), Queue()
pool.submit(enqueue_output, p.stdout, q_stdout)
pool.submit(enqueue_output, p.stderr, q_stderr)
while True:
if p.poll() is not None and q_stdout.empty() and q_stderr.empty():
break
out_line = err_line = ''
try:
out_line = q_stdout.get_nowait()
except Empty:
pass
try:
err_line = q_stderr.get_nowait()
except Empty:
pass
yield (out_line, err_line)
Run Code Online (Sandbox Code Playgroud)
read_popen_pipes() 正在使用:
import subprocess as sp
with sp.Popen(my_cmd, stdout=sp.PIPE, stderr=sp.PIPE, text=True) as p:
for out_line, err_line in read_popen_pipes(p):
# Do stuff with each line, e.g.:
print(out_line, end='')
print(err_line, end='')
return p.poll() # return status-code
Run Code Online (Sandbox Code Playgroud)
自 2010 年以来,该subprocess模块已经取得了长足的进步,这里的大多数答案都已经过时了。
这是适用于现代 Python 版本的简单方法:
from subprocess import Popen, PIPE, STDOUT
with Popen(args, stdout=PIPE, stderr=STDOUT, text=True) as proc:
for line in proc.stdout:
print(line)
rc = proc.returncode
Run Code Online (Sandbox Code Playgroud)
关于用作Popen上下文管理器(自 Python 3.2 起支持):在with块退出时,标准文件描述符将关闭,并且进程将等待/设置 returncode 属性。请参阅subprocess.py:Popen.__exit__CPython 源代码。
您还可以读取不带循环的行。适用于 python3.6。
import os
import subprocess
process = subprocess.Popen(command, stdout=subprocess.PIPE)
list_of_byte_strings = process.stdout.readlines()
Run Code Online (Sandbox Code Playgroud)
Pythont 3.5在模块中添加了方法run()和,两者都返回一个对象。有了这个,你就可以使用:call()subprocessCompletedProcessproc.stdout.splitlines()
proc = subprocess.run( comman, shell=True, capture_output=True, text=True, check=True )
for line in proc.stdout.splitlines():
print "stdout:", line
Run Code Online (Sandbox Code Playgroud)
另请参阅如何使用子进程运行方法在 Python 中执行 Shell 命令
| 归档时间: |
|
| 查看次数: |
316260 次 |
| 最近记录: |