23

私は電話からつかもうとしてstdoutいますが、これは次のsubprocess.Popenようにして簡単に達成できます。

cmd = subprocess.Popen('ls -l', shell=True, stdout=PIPE)
for line in cmd.stdout.readlines():
    print line

stdout「リアルタイム」でつかみたいです。上記の方法では、PIPEはすべてを取得するのを待ってからstdout戻ります。

したがって、ロギングの目的では、これは私の要件を満たしていません(たとえば、発生中に何が起こっているかを「確認」します)。

実行中に行ごとに取得する方法はありstdoutますか?または、これはの制限ですか(閉じるsubprocessまで待たなければなりません)。PIPE

編集 私が切り替えるreadlines()と、 (理想的readline()ではない)最後の行だけが表示されます:stdout

In [75]: cmd = Popen('ls -l', shell=True, stdout=PIPE)
In [76]: for i in cmd.stdout.readline(): print i
....: 
t
o
t
a
l

1
0
4
4

8 に答える 8

22

インタプリタがバッファリングしています。printステートメントの後にsys.stdout.flush()への呼び出しを追加します。

于 2010-02-26T21:41:31.327 に答える
17

実際、実際の解決策は、サブプロセスのstdoutをプロセスのstdoutに直接リダイレクトすることです。

実際、あなたのソリューションでは、たとえば、stdoutのみを印刷でき、stderrは同時に印刷できません。

import sys
from subprocess import Popen
Popen("./slow_cmd_output.sh", stdout=sys.stdout, stderr=sys.stderr).communicate()

これcommunicate()は、サブプロセスが終了するまで呼び出しをブロックするためです。そうしないと、次の行に直接移動し、サブプロセスの前にプログラムが終了する可能性があります(ただし、Pythonスクリプトが閉じた後でも、stdoutへのリダイレクトは機能します) 、私はそれをテストしました)。

このようにして、たとえば、stdoutとstderrの両方を、絶対リアルタイムでリダイレクトします。

たとえば、私の場合、次のスクリプトでテストしましたslow_cmd_output.sh

#!/bin/bash

for i in 1 2 3 4 5 6; do sleep 5 && echo "${i}th output" && echo "err output num ${i}" >&2; done
于 2014-06-09T19:30:27.813 に答える
11

「リアルタイム」で出力を取得subprocessすることは、他のプロセスのバッファリング戦略を打ち負かすことはできないため、不適切です。そのため、このような「リアルタイム」の出力グラブが必要な場合は常に(スタックオーバーフローに関するよくある質問です!)、代わりにpexpectを使用することをお勧めします(Windows以外のすべての場所-Windowsではwexpect)。

于 2010-01-18T01:30:31.473 に答える
3

出力を合体させているreadlines()をドロップします。また、ほとんどのコマンドはパイプへの出力を内部的にバッファリングするため、ラインバッファリングを強制する必要があります。詳細については、http ://www.pixelbeat.org/programming/stdio_buffering/を参照してください。

于 2010-01-17T22:31:11.330 に答える
3

これは私が何日も答えを探していた質問なので、フォローしている人のためにここに残したいと思いました。他のプロセスのバッファリング戦略に対抗できないことは事実ですsubprocessが、を使用して別のPythonスクリプトを呼び出す場合は、バッファリングされていないPythonsubprocess.Popenを開始するように指示できます。

command = ["python", "-u", "python_file.py"]
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

for line in iter(p.stdout.readline, ''):
    line = line.replace('\r', '').replace('\n', '')
    print line
    sys.stdout.flush()

私はまた、popenの議論が隠されたものを公開するのを手伝ったケースを見bufsize=1てきました。universal_newlines=Truestdout

于 2013-05-06T18:26:33.687 に答える
1
cmd = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE)
for line in cmd.stdout:
    print line.rstrip("\n")
于 2010-01-17T22:13:24.030 に答える
0

の呼び出しreadlinesは、プロセスが終了するのを待っています。これをループアラウンドcmd.stdout.readline()(単数に注意)に置き換えれば、すべてうまくいくはずです。

于 2010-01-17T22:09:27.273 に答える
0

すでに述べたように、問題は、端末がプロセスに接続されていない場合のstdioライブラリのprintflikeステートメントのバッファリングにあります。とにかく、Windowsプラットフォームでこれを回避する方法があります。他のプラットフォームでも同様の解決策があるかもしれません。

Windowsでは、プロセスの作成時に新しいコンソールを強制的に作成できます。良い点は、これを非表示のままにして、表示されないようにすることです(これは、サブプロセスモジュール内でshell = Trueによって実行されます)。

cmd = subprocess.Popen('ls -l', shell=True, stdout=PIPE, creationflags=_winapi.CREATE_NEW_CONSOLE, bufsize=1, universal_newlines=True)
for line in cmd.stdout.readlines():
    print line

また

もう少し完全な解決策は、STARTUPINFOパラメータを明示的に設定して、shell=Trueが上記で行った新しい不要なcmd.exeシェルプロセスの起動を防ぐことです。

class PopenBackground(subprocess.Popen):
    def __init__(self, *args, **kwargs):

        si = kwargs.get('startupinfo', subprocess.STARTUPINFO())
        si.dwFlags |= _winapi.STARTF_USESHOWWINDOW
        si.wShowWindow = _winapi.SW_HIDE

        kwargs['startupinfo'] = si
        kwargs['creationflags'] = kwargs.get('creationflags', 0) | _winapi.CREATE_NEW_CONSOLE
        kwargs['bufsize'] = 1
        kwargs['universal_newlines'] = True

        super(PopenBackground, self).__init__(*args, **kwargs)

process = PopenBackground(['ls', '-l'], stdout=subprocess.PIPE)
    for line in cmd.stdout.readlines():
        print line
于 2015-09-12T12:43:06.750 に答える