我使用python脚本作为流体动力学代码的驱动程序。当运行模拟时,我使用subprocess.Popen
来运行代码,将stdout和stderr的输出收集到subprocess.PIPE
---然后我就可以打印(并保存到日志文件中) )输出信息,并检查是否有任何错误。问题是,我不知道代码是如何进展的。如果我直接从命令行运行它,它会给我输出关于它的迭代次数,时间,下一个时间步长等等。
有没有办法存储输出(用于记录和错误检查),还能产生实时流输出?
我的代码的相关部分:
ret_val = subprocess.Popen( run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True )
output, errors = ret_val.communicate()
log_file.write(output)
print output
if( ret_val.returncode ):
print "RUN failed\n\n%s\n\n" % (errors)
success = False
if( errors ): log_file.write("\n\n%s\n\n" % errors)
最初我正在管道run_command
到tee
,以便副本直接进入日志文件,并且流仍然直接输出到终端 - 但这样我就无法存储任何错误(对我的知识)。
编辑:
临时解决方案:
ret_val = subprocess.Popen( run_command, stdout=log_file, stderr=subprocess.PIPE, shell=True )
while not ret_val.poll():
log_file.flush()
然后,在另一个终端中,运行tail -f log.txt
(s.t。log_file = 'log.txt'
)。
答案 0 :(得分:135)
您可以通过两种方式执行此操作,方法是从read
或readline
函数创建迭代器并执行:
import subprocess
import sys
with open('test.log', 'w') as f: # replace 'w' with 'wb' for Python 3
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for c in iter(lambda: process.stdout.read(1), ''): # replace '' with b'' for Python 3
sys.stdout.write(c)
f.write(c)
或
import subprocess
import sys
with open('test.log', 'w') as f: # replace 'w' with 'wb' for Python 3
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for line in iter(process.stdout.readline, ''): # replace '' with b'' for Python 3
sys.stdout.write(line)
f.write(line)
或者您可以创建reader
和writer
文件。将writer
传递给Popen
,然后阅读reader
import io
import time
import subprocess
import sys
filename = 'test.log'
with io.open(filename, 'wb') as writer, io.open(filename, 'rb', 1) as reader:
process = subprocess.Popen(command, stdout=writer)
while process.poll() is None:
sys.stdout.write(reader.read())
time.sleep(0.5)
# Read the remaining
sys.stdout.write(reader.read())
这样,您将在test.log
以及标准输出中写入数据。
文件方法的唯一优点是您的代码不会阻止。因此,您可以在此期间执行任何操作,并以非阻塞方式从reader
随时阅读。当您使用PIPE
时,read
和readline
函数将被阻塞,直到将一个字符写入管道或分别将一行写入管道。
答案 1 :(得分:76)
subprocess.PIPE
时,它很容易,否则很难。< / H2>
可能是时候解释一下subprocess.Popen
如何做到这一点。
(警告:这是针对Python 2.x,尽管3.x类似;而且我在Windows变体上非常模糊。我更了解POSIX的东西。)
Popen
函数需要同时处理零到三个I / O流。这些通常表示为stdin
,stdout
和stderr
。
您可以提供:
None
,表示您不想重定向流。它将像往常一样继承这些。请注意,至少在POSIX系统上,这并不意味着它将使用Python的sys.stdout
,而只是Python的实际的标准输出;见最后的演示。int
值。这是一个&#34; raw&#34;文件描述符(至少在POSIX中)。 (旁注:PIPE
和STDOUT
实际上是int
内部,但是&#34;不可能&#34;描述符,-1和-2。)fileno
方法的对象。 Popen
将使用stream.fileno()
找到该流的描述符,然后继续int
值。subprocess.PIPE
,表示Python应该创建一个管道。subprocess.STDOUT
(仅适用于stderr
):告诉Python使用与stdout
相同的描述符。只有在为None
提供(非stdout
)值时才有意义,即使这样,如果设置stdout=subprocess.PIPE
,也只需要 。 (否则,您只能提供为stdout
提供的相同参数,例如Popen(..., stdout=stream, stderr=stream)
。)如果您没有重定向任何内容(将所有三个保留为默认None
值或提供显式None
),Pipe
使其变得非常简单。它只需要分离子进程并让它运行。或者,如果您重定向到非PIPE
- int
或流fileno()
- 它仍然很容易,因为操作系统可以完成所有工作。 Python只需要分离子进程,将其stdin,stdout和/或stderr连接到提供的文件描述符。
如果只重定向一个流,Pipe
仍然很容易。让我们一次选择一个流并观看。
假设您要提供一些stdin
,但让stdout
和stderr
取消重定向,或转到文件描述符。作为父进程,您的Python程序只需使用write()
向管道发送数据。你可以自己做,例如:
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE)
proc.stdin.write('here, have some data\n') # etc
或者您可以将标准输入数据传递给proc.communicate()
,然后执行上面显示的stdin.write
。没有输出回来,因此communicate()
只有一个其他实际工作:它也会为你关闭管道。 (如果您不打电话proc.communicate()
,则必须致电proc.stdin.close()
关闭管道,以便子流程知道没有更多数据通过。)
假设您要捕获stdout
,但只留下stdin
和stderr
。同样,这很简单:只需调用proc.stdout.read()
(或等效的),直到没有更多的输出。由于proc.stdout()
是普通的Python I / O流,因此您可以使用它上面的所有常规构造,例如:
for line in proc.stdout:
或者,您可以再次使用proc.communicate()
,只为read()
执行此操作。
如果您只想捕获stderr
,则其效果与stdout
相同。
在事情变得艰难之前还有一招。假设您要捕获stdout
,并在与stdout相同的管道上捕获stderr
但:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
在这种情况下,subprocess
&#34;作弊&#34;!好吧,它必须这样做,所以它并没有真正作弊:它启动子进程,其stdout和stderr都指向(单个)管道描述符,反馈给它的父(Python)进程。在父端,只有一个管道描述符用于读取输出。所有&#34; stderr&#34;输出显示在proc.stdout
中,如果调用proc.communicate()
,则stderr结果(元组中的第二个值)将为None
,而不是字符串。
当您想要使用至少两个管道时,所有问题都会出现。事实上,subprocess
代码本身就有这一点:
def communicate(self, input=None):
...
# Optimization: If we are only using one pipe, or no pipe at
# all, using select() or threads is unnecessary.
if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
但是,唉,在这里我们至少有两个,也许是三个不同的管道,所以count(None)
返回1或0.我们必须努力做到。
在Windows上,这使用threading.Thread
累积self.stdout
和self.stderr
的结果,并让父线程传递self.stdin
输入数据(然后关闭管道)。
在POSIX上,如果可用,则使用poll
,否则使用select
来累积输出并传递stdin输入。所有这些都在(单个)父进程/线程中运行。
此处需要线程或轮询/选择以避免死锁。例如,假设我们已将所有三个流重定向到三个单独的管道。进一步假设在写入过程暂停之前,可以将多少数据填入管道,等待读取过程“清除”&#34;从另一端的管道。我们将这个小限制设置为单个字节,仅用于说明。 (这实际上是如何工作的,除了限制远大于一个字节。)
如果父(Python)进程尝试写几个字节 - 比如'go\n'
到proc.stdin
,第一个字节进入,然后第二个进程导致Python进程暂停,等待子进程读取第一个字节,清空管道。
同时,假设子进程决定打印一个友好的&#34;你好!不要恐慌!&#34;问候。 H
进入其标准输出管道,但e
导致它暂停,等待其父级读取H
,清空标准输出管道。
现在我们陷入困境:Python进程已经睡着了,等待完成说&#34;去&#34;,子进程也睡着了,等待完成说&#34;你好!不要恐慌!&#34;。
subprocess.Popen
代码避免了线程或选择/轮询的这个问题。当字节可以越过管道时,它们就会消失。当它们不能时,只有一个线程(不是整个进程)必须休眠 - 或者在select / poll的情况下,Python进程同时等待&#34;可以写&#34;或者&#34;可用的数据&#34;,仅当有空间时写入进程的stdin,并且仅在数据准备好时才读取其stdout和/或stderr。 proc.communicate()
代码(处理多毛案例的实际_communicate
)返回一旦所有stdin数据(如果有)已经发送并且所有stdout和/或stderr数据已经累积。
如果要在两个不同的管道上读取stdout
和stderr
(无论任何stdin
重定向),您还需要避免死锁。这里的死锁场景是不同的 - 当你从stderr
提取数据时,子进程将某些内容写入stdout
时会发生这种情况,反之亦然 - 但它仍然存在。< / p>
我承诺会证明,未重定向,Python subprocess
会写入底层标准输出,而不是sys.stdout
。所以,这里有一些代码:
from cStringIO import StringIO
import os
import subprocess
import sys
def show1():
print 'start show1'
save = sys.stdout
sys.stdout = StringIO()
print 'sys.stdout being buffered'
proc = subprocess.Popen(['echo', 'hello'])
proc.wait()
in_stdout = sys.stdout.getvalue()
sys.stdout = save
print 'in buffer:', in_stdout
def show2():
print 'start show2'
save = sys.stdout
sys.stdout = open(os.devnull, 'w')
print 'after redirect sys.stdout'
proc = subprocess.Popen(['echo', 'hello'])
proc.wait()
sys.stdout = save
show1()
show2()
运行时:
$ python out.py
start show1
hello
in buffer: sys.stdout being buffered
start show2
hello
请注意,如果添加stdout=sys.stdout
,则第一个例程将失败,因为StringIO
对象没有fileno
。如果您添加hello
,则第二个将省略stdout=sys.stdout
,因为sys.stdout
已被重定向到os.devnull
。
(如果您重定向Python的文件描述符-1,则子进程将遵循该重定向。open(os.devnull, 'w')
调用会生成fileno()
更大的流比2。)
答案 2 :(得分:17)
我们也可以使用默认文件迭代器来读取stdout而不是使用带有readline()的iter构造。
import subprocess
import sys
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
for line in process.stdout:
sys.stdout.write(line)
答案 3 :(得分:10)
如果您能够使用第三方库,您可以使用类似sarge
的内容(披露:我是它的维护者)。该库允许对来自子进程的输出流进行非阻塞访问 - 它在subprocess
模块上分层。
答案 4 :(得分:2)
一个好但“重量级”的解决方案是使用Twisted - 见底部。
如果你愿意只接受stdout,那么这些行应该有效:
import subprocess
import sys
popenobj = subprocess.Popen(["ls", "-Rl"], stdout=subprocess.PIPE)
while not popenobj.poll():
stdoutdata = popenobj.stdout.readline()
if stdoutdata:
sys.stdout.write(stdoutdata)
else:
break
print "Return code", popenobj.returncode
(如果你使用read()它会尝试读取整个“文件”,这是无用的,我们真正可以使用的是读取管道中所有数据的东西)
人们也可能试图通过线程来解决这个问题,例如:
import subprocess
import sys
import threading
popenobj = subprocess.Popen("ls", stdout=subprocess.PIPE, shell=True)
def stdoutprocess(o):
while True:
stdoutdata = o.stdout.readline()
if stdoutdata:
sys.stdout.write(stdoutdata)
else:
break
t = threading.Thread(target=stdoutprocess, args=(popenobj,))
t.start()
popenobj.wait()
t.join()
print "Return code", popenobj.returncode
现在我们可以通过两个线程添加stderr。
但请注意,子进程文档不鼓励直接使用这些文件,并建议使用communicate()
(主要关注死锁,我认为这不是上面的问题),解决方案有点笨拙,所以看起来真的很像strong>子流程模块不太适合工作(另见:http://www.python.org/dev/peps/pep-3145/),我们需要查看其他内容。
更复杂的解决方案是使用Twisted,如下所示:https://twistedmatrix.com/documents/11.1.0/core/howto/process.html
使用Twisted执行此操作的方法是使用reactor.spawnprocess()
创建流程并提供ProcessProtocol
,然后异步处理输出。 Twisted示例Python代码位于:https://twistedmatrix.com/documents/11.1.0/core/howto/listings/process/process.py
答案 5 :(得分:1)
我尝试的所有上述解决方案都无法分离stderr和stdout输出(多个管道)或者当OS管道缓冲区已满时永远被阻塞,这在您运行的命令输出太快时发生(有警告这是关于子程序的python poll()手册)。我找到的唯一可靠的方法是通过select,但这只是一个posix解决方案:
import subprocess
import sys
import os
import select
# returns command exit status, stdout text, stderr text
# rtoutput: show realtime output while running
def run_script(cmd,rtoutput=0):
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
poller = select.poll()
poller.register(p.stdout, select.POLLIN)
poller.register(p.stderr, select.POLLIN)
coutput=''
cerror=''
fdhup={}
fdhup[p.stdout.fileno()]=0
fdhup[p.stderr.fileno()]=0
while sum(fdhup.values()) < len(fdhup):
try:
r = poller.poll(1)
except select.error, err:
if err.args[0] != EINTR:
raise
r=[]
for fd, flags in r:
if flags & (select.POLLIN | select.POLLPRI):
c = os.read(fd, 1024)
if rtoutput:
sys.stdout.write(c)
sys.stdout.flush()
if fd == p.stderr.fileno():
cerror+=c
else:
coutput+=c
else:
fdhup[fd]=1
return p.poll(), coutput.strip(), cerror.strip()
答案 6 :(得分:1)
如果您只需要输出将在控制台上可见,那么对我来说最简单的解决方案是将以下参数传递给 foldMap ($ succ indentation) xs
Popen
这将使用你的 python 脚本 stdio 文件句柄
答案 7 :(得分:1)
看起来行缓冲输出对您有用,在这种情况下,类似下面的内容可能适用。 (警告:它未经测试。)这只会实时给出子进程的标准输出。如果你想实时同时使用stderr和stdout,你必须使用select
做一些更复杂的事情。
proc = subprocess.Popen(run_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
while proc.poll() is None:
line = proc.stdout.readline()
print line
log_file.write(line + '\n')
# Might still be data on stdout at this point. Grab any
# remainder.
for line in proc.stdout.read().split('\n'):
print line
log_file.write(line + '\n')
# Do whatever you want with proc.stderr here...
答案 8 :(得分:0)
这是我在其中一个项目中使用的课程。它将子进程的输出重定向到日志。起初我尝试简单地覆盖写入方法,但这不起作用,因为子进程永远不会调用它(重定向发生在filedescriptor级别)。所以我使用自己的管道,类似于在子进程模块中完成的管道。这样做的好处是可以将所有日志记录/打印逻辑封装在适配器中,您只需将记录器的实例传递给Popen
:subprocess.Popen("/path/to/binary", stderr = LogAdapter("foo"))
class LogAdapter(threading.Thread):
def __init__(self, logname, level = logging.INFO):
super().__init__()
self.log = logging.getLogger(logname)
self.readpipe, self.writepipe = os.pipe()
logFunctions = {
logging.DEBUG: self.log.debug,
logging.INFO: self.log.info,
logging.WARN: self.log.warn,
logging.ERROR: self.log.warn,
}
try:
self.logFunction = logFunctions[level]
except KeyError:
self.logFunction = self.log.info
def fileno(self):
#when fileno is called this indicates the subprocess is about to fork => start thread
self.start()
return self.writepipe
def finished(self):
"""If the write-filedescriptor is not closed this thread will
prevent the whole program from exiting. You can use this method
to clean up after the subprocess has terminated."""
os.close(self.writepipe)
def run(self):
inputFile = os.fdopen(self.readpipe)
while True:
line = inputFile.readline()
if len(line) == 0:
#no new data was added
break
self.logFunction(line.strip())
如果您不需要记录但只是想使用print()
,您显然可以删除大部分代码并使类更短。您也可以使用__enter__
和__exit__
方法展开它,并在finished
中调用__exit__
,以便您可以轻松地将其用作上下文。
答案 9 :(得分:0)
为什么不直接将stdout
设置为sys.stdout
?如果您还需要输出到日志,那么您可以简单地覆盖f。
import sys
import subprocess
class SuperFile(open.__class__):
def write(self, data):
sys.stdout.write(data)
super(SuperFile, self).write(data)
f = SuperFile("log.txt","w+")
process = subprocess.Popen(command, stdout=f, stderr=f)
答案 10 :(得分:0)
除了所有这些答案之外,一种简单的方法还可以如下:
process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
while process.stdout.readable():
line = process.stdout.readline()
if not line:
break
print(line.strip())
只要可读流就循环遍历可读流,如果得到空结果,则将其停止。
这里的关键是,readline()
返回一行(末尾为\n
),只要有输出就行,如果确实在末尾则为空。
希望这对某人有帮助。
答案 11 :(得分:0)
类似于先前的答案,但是以下解决方案在使用Python3的Windows上为我工作,以提供一种通用的实时打印和登录方法(getting-realtime-output-using-python):
def print_and_log(command, logFile):
with open(logFile, 'wb') as f:
command = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
while True:
output = command.stdout.readline()
if not output and command.poll() is not None:
f.close()
break
if output:
f.write(output)
print(str(output.strip(), 'utf-8'), flush=True)
return command.poll()
答案 12 :(得分:0)
基于上述所有内容,我建议对版本进行略微修改(python3):
None
后不需要重复处理读取的数据代码:
import subprocess
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, universal_newlines=True)
while True:
rd = proc.stdout.readline()
print(rd, end='') # and whatever you want to do...
if not rd: # EOF
returncode = proc.poll()
if returncode is not None:
break
time.sleep(0.1) # cmd closed stdout, but not exited yet
# You may want to check on ReturnCode here
答案 13 :(得分:0)
我认为subprocess.communicate
方法有点误导:它实际上填充了您在subprocess.Popen
中指定的 stdout 和 stderr 。
但是,从subprocess.PIPE
中读取的内容可以提供给subprocess.Popen
的 stdout 和 stderr 参数,最终将填满OS管道缓冲和死锁您的应用程序(特别是如果您有多个必须使用subprocess
的进程/线程)。
我建议的解决方案是为 stdout 和 stderr 提供文件-并读取文件的内容,而不是从死锁的PIPE
中读取文件。这些文件可以是tempfile.NamedTemporaryFile()
-由subprocess.communicate
写入文件时也可以对其进行读取。
以下是示例用法:
try:
with ProcessRunner(('python', 'task.py'), env=os.environ.copy(), seconds_to_wait=0.01) as process_runner:
for out in process_runner:
print(out)
catch ProcessError as e:
print(e.error_message)
raise
这是源代码,已准备好使用,其中包含了我可以提供的注释,以解释其作用:
如果您使用的是python 2,请确保首先从pypi安装最新版本的 subprocess32 软件包。
import os
import sys
import threading
import time
import tempfile
import logging
if os.name == 'posix' and sys.version_info[0] < 3:
# Support python 2
import subprocess32 as subprocess
else:
# Get latest and greatest from python 3
import subprocess
logger = logging.getLogger(__name__)
class ProcessError(Exception):
"""Base exception for errors related to running the process"""
class ProcessTimeout(ProcessError):
"""Error that will be raised when the process execution will exceed a timeout"""
class ProcessRunner(object):
def __init__(self, args, env=None, timeout=None, bufsize=-1, seconds_to_wait=0.25, **kwargs):
"""
Constructor facade to subprocess.Popen that receives parameters which are more specifically required for the
Process Runner. This is a class that should be used as a context manager - and that provides an iterator
for reading captured output from subprocess.communicate in near realtime.
Example usage:
try:
with ProcessRunner(('python', task_file_path), env=os.environ.copy(), seconds_to_wait=0.01) as process_runner:
for out in process_runner:
print(out)
catch ProcessError as e:
print(e.error_message)
raise
:param args: same as subprocess.Popen
:param env: same as subprocess.Popen
:param timeout: same as subprocess.communicate
:param bufsize: same as subprocess.Popen
:param seconds_to_wait: time to wait between each readline from the temporary file
:param kwargs: same as subprocess.Popen
"""
self._seconds_to_wait = seconds_to_wait
self._process_has_timed_out = False
self._timeout = timeout
self._process_done = False
self._std_file_handle = tempfile.NamedTemporaryFile()
self._process = subprocess.Popen(args, env=env, bufsize=bufsize,
stdout=self._std_file_handle, stderr=self._std_file_handle, **kwargs)
self._thread = threading.Thread(target=self._run_process)
self._thread.daemon = True
def __enter__(self):
self._thread.start()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._thread.join()
self._std_file_handle.close()
def __iter__(self):
# read all output from stdout file that subprocess.communicate fills
with open(self._std_file_handle.name, 'r') as stdout:
# while process is alive, keep reading data
while not self._process_done:
out = stdout.readline()
out_without_trailing_whitespaces = out.rstrip()
if out_without_trailing_whitespaces:
# yield stdout data without trailing \n
yield out_without_trailing_whitespaces
else:
# if there is nothing to read, then please wait a tiny little bit
time.sleep(self._seconds_to_wait)
# this is a hack: terraform seems to write to buffer after process has finished
out = stdout.read()
if out:
yield out
if self._process_has_timed_out:
raise ProcessTimeout('Process has timed out')
if self._process.returncode != 0:
raise ProcessError('Process has failed')
def _run_process(self):
try:
# Start gathering information (stdout and stderr) from the opened process
self._process.communicate(timeout=self._timeout)
# Graceful termination of the opened process
self._process.terminate()
except subprocess.TimeoutExpired:
self._process_has_timed_out = True
# Force termination of the opened process
self._process.kill()
self._process_done = True
@property
def return_code(self):
return self._process.returncode
答案 14 :(得分:0)
没有一个Pythonic解决方案对我有用。
事实证明,proc.stdout.read()
或类似名称可能会永远阻止。
因此,我像这样使用tee
:
subprocess.run('./my_long_running_binary 2>&1 | tee -a my_log_file.txt && exit ${PIPESTATUS}', shell=True, check=True, executable='/bin/bash')
如果您已经在使用shell=True
,则此解决方案很方便。
${PIPESTATUS}
捕获整个命令链的成功状态(仅在Bash中可用)。
如果我省略了&& exit ${PIPESTATUS}
,那么它将始终返回零,因为tee
永远不会失败。
unbuffer
对于将每一行立即打印到终端中可能是必要的,而不是等到“管道缓冲区”被填满就等待太长时间。
但是,unbuffer吞没了assert(SIG Abort)的退出状态...
2>&1
还将stderror记录到文件中。
答案 15 :(得分:0)
解决方案1:实时同时记录stdout
和stderr
一种简单的解决方案,可以同时实时记录stdout
和stderr
。
import subprocess as sp
from concurrent.futures import ThreadPoolExecutor
def log_popen_pipe(p, pipe_name):
while p.poll() is None:
line = getattr(p, pipe_name).readline()
log_file.write(line)
with sp.Popen(my_cmd, stdout=sp.PIPE, stderr=sp.PIPE, text=True) as p:
with ThreadPoolExecutor(2) as pool:
r1 = pool.submit(log_popen_pipe, p, 'stdout')
r2 = pool.submit(log_popen_pipe, p, 'stderr')
r1.result()
r2.result()
解决方案2:创建一个迭代器,该迭代器实时并发地逐行返回stdout
和stderr
我们在这里创建了一个函数read_popen_pipes()
,该函数可让您实时并发地遍历两个管道(stdout
/ stderr
):
import subprocess as sp
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:
out_line = err_line = ''
try:
out_line = q_stdout.get_nowait()
err_line = q_stderr.get_nowait()
except Empty:
pass
yield (out_line, err_line)
if p.poll() is not None:
break
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):
print(out_line, end='')
print(err_line, end='')
return p.poll()
答案 16 :(得分:0)
import os
def execute(cmd, callback):
for line in iter(os.popen(cmd).readline, ''):
callback(line[:-1])
execute('ls -a', print)