簡體   English   中英

Jupyter 筆記本中 Python 子進程的實時標准輸出輸出

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM