[英]Live stdout output from Python subprocess in Jupyter notebook
我正在使用子进程从 Python (3.5.2) 脚本运行命令行程序,我在 Jupyter 笔记本中运行该脚本。 子进程需要很长时间才能运行,因此我希望将其标准输出实时打印到 Jupyter 笔记本的屏幕上。
在从终端运行的普通 Python 脚本中,我可以毫无问题地做到这一点。 我这样做使用:
def run_command(cmd):
from subprocess import Popen, PIPE
import shlex
with Popen(shlex.split(cmd), stdout=PIPE, bufsize=1, universal_newlines=True) as p:
for line in p.stdout:
print(line, end='')
exit_code = p.poll()
return exit_code
但是,当我在 Jupyter 笔记本中运行脚本时,它不会将标准输出实时打印到屏幕上。 相反,它会在子进程完成运行后打印所有内容。
有没有人对如何解决这个问题有任何想法?
非常感谢,约翰尼
ipython notebook 有自己的运行 shell 命令支持。 如果你不需要用子进程的东西来捕获你可以做的
cmd = 'ls -l'
!{cmd}
使用 ! 执行的命令的输出自动通过笔记本传输。
如果您设置stdout = None
(这是默认值,因此您可以完全省略stdout
参数),那么您的进程应该将其输出写入运行您的 IPython 笔记本服务器的终端。
发生这种情况是因为子进程的默认行为是从父文件处理程序继承的(请参阅文档)。
您的代码如下所示:
from subprocess import Popen, PIPE
import shlex
def run_command(cmd):
p = Popen(shlex.split(cmd), bufsize=1, universal_newlines=True)
return p.poll()
这不会打印到浏览器中的笔记本,但至少您将能够在其他代码运行时异步查看子进程的输出。
希望这会有所帮助。
Jupyter 使用标准输出和标准错误。 这应该会得到您想要的结果,并在命令无法启动时为您提供一个更有用的异常。
import signal
import subprocess as sp
class VerboseCalledProcessError(sp.CalledProcessError):
def __str__(self):
if self.returncode and self.returncode < 0:
try:
msg = "Command '%s' died with %r." % (
self.cmd, signal.Signals(-self.returncode))
except ValueError:
msg = "Command '%s' died with unknown signal %d." % (
self.cmd, -self.returncode)
else:
msg = "Command '%s' returned non-zero exit status %d." % (
self.cmd, self.returncode)
return f'{msg}\n' \
f'Stdout:\n' \
f'{self.output}\n' \
f'Stderr:\n' \
f'{self.stderr}'
def bash(cmd, print_stdout=True, print_stderr=True):
proc = sp.Popen(cmd, stderr=sp.PIPE, stdout=sp.PIPE, shell=True, universal_newlines=True,
executable='/bin/bash')
all_stdout = []
all_stderr = []
while proc.poll() is None:
for stdout_line in proc.stdout:
if stdout_line != '':
if print_stdout:
print(stdout_line, end='')
all_stdout.append(stdout_line)
for stderr_line in proc.stderr:
if stderr_line != '':
if print_stderr:
print(stderr_line, end='', file=sys.stderr)
all_stderr.append(stderr_line)
stdout_text = ''.join(all_stdout)
stderr_text = ''.join(all_stderr)
if proc.wait() != 0:
raise VerboseCalledProcessError(proc.returncode, cmd, stdout_text, stderr_text)
用显式readline()
调用替换 for 循环对我readline()
。
from subprocess import Popen, PIPE
import shlex
def run_command(cmd):
with Popen(shlex.split(cmd), stdout=PIPE, bufsize=1, universal_newlines=True) as p:
while True:
line = p.stdout.readline()
if not line:
break
print(line)
exit_code = p.poll()
return exit_code
即使在 4 年后,他们的迭代器仍有一些问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.