78

コマンドの出力をコンソールから非表示にせずにファイルに保存できるようにする Python ソリューションを探しています。

参考までに:私は、(Unix コマンド ライン ユーティリティとしての) teeについて質問していますが、Python intertools モジュールの同じ名前の関数については質問していません。

詳細

  • Python ソリューション ( を呼び出しteeていません。Windows では使用できません)
  • 呼び出されたプロセスの標準入力に入力を提供する必要はありません
  • 呼び出されたプログラムを制御できません。私が知っているのは、stdout と stderr に何かを出力し、終了コードで戻るということだけです。
  • 外部プログラム(サブプロセス)呼び出し時に動作させるには
  • 両方のために働くためstderrstdout
  • stdout と stderr を区別できるのは、コンソールに 1 つだけを表示したい場合や、別の色を使用して stderr を出力しようとする場合があるためです。これは機能しstderr = subprocess.STDOUTないことを意味します。
  • ライブ出力 (プログレッシブ) - プロセスは長時間実行される可能性があり、終了するのを待つことができません。
  • Python 3 互換コード (重要)

参考文献

これまでに見つけたいくつかの不完全なソリューションを次に示します。

ダイアグラム http://blog.i18n.ro/wp-content/uploads/2010/06/Drawing_tee_py.png

現在のコード (2 回目の試行)

#!/usr/bin/python
from __future__ import print_function

import sys, os, time, subprocess, io, threading
cmd = "python -E test_output.py"

from threading import Thread
class StreamThread ( Thread ):
    def __init__(self, buffer):
        Thread.__init__(self)
        self.buffer = buffer
    def run ( self ):
        while 1:
            line = self.buffer.readline()
            print(line,end="")
            sys.stdout.flush()
            if line == '':
                break

proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutThread = StreamThread(io.TextIOWrapper(proc.stdout))
stderrThread = StreamThread(io.TextIOWrapper(proc.stderr))
stdoutThread.start()
stderrThread.start()
proc.communicate()
stdoutThread.join()
stderrThread.join()

print("--done--")

#### test_output.py ####

#!/usr/bin/python
from __future__ import print_function
import sys, os, time

for i in range(0, 10):
    if i%2:
        print("stderr %s" % i, file=sys.stderr)
    else:
        print("stdout %s" % i, file=sys.stdout)
    time.sleep(0.1)
実質出力
stderr 1
stdout 0
stderr 3
stdout 2
stderr 5
stdout 4
stderr 7
stdout 6
stderr 9
stdout 8
--done--

予想される出力は、行が順序付けられていることでした。Popen を 1 つの PIPE のみを使用するように変更することは許可されていないことに注意してください。

また、2番目のケースでもリアルタイムのようなアウトを取得できませんでしたが、実際にはプロセスが終了したときにすべての結果が受信されました. デフォルトでは、Popen はバッファーを使用しません (bufsize=0)。

4

6 に答える 6

13

これはかなり古い投稿だと思いますが、誰かがまだこれを行う方法を探している場合に備えて:

proc = subprocess.Popen(["ping", "localhost"], 
                        stdout=subprocess.PIPE, 
                        stderr=subprocess.PIPE)

with open("logfile.txt", "w") as log_file:
  while proc.poll() is None:
     line = proc.stderr.readline()
     if line:
        print "err: " + line.strip()
        log_file.write(line)
     line = proc.stdout.readline()
     if line:
        print "out: " + line.strip()
        log_file.write(line)
于 2012-07-27T13:18:09.167 に答える
7

teeこれはPythonへの簡単な移植です。

import sys
sinks = sys.argv[1:]
sinks = [open(sink, "w") for sink in sinks]
sinks.append(sys.stderr)
while True:
  input = sys.stdin.read(1024)
  if input:
    for sink in sinks:
      sink.write(input)
  else:
    break

私は現在Linuxで実行していますが、これはほとんどのプラットフォームで機能するはずです。


さて、このsubprocess部分については、サブプロセスをどのように「ワイヤリング」するか、および、、、およびファイルシンクにどのように「ワイヤリング」するかはわかりませんがstdinstdoutこれを実行できることはわかっています。stderrstdinstdoutstderr

import subprocess
callee = subprocess.Popen( ["python", "-i"],
                           stdin = subprocess.PIPE,
                           stdout = subprocess.PIPE,
                           stderr = subprocess.PIPE
                         )

これで、通常のファイルと同様callee.stdinに、にアクセスして、上記の「ソリューション」を機能させることができます。を取得したい場合は、に追加の呼び出しを行う必要があります。callee.stdoutcallee.stderrcallee.returncodecallee.poll()

に書き込むときは注意してくださいcallee.stdin:それを行ったときにプロセスが終了した場合、エラーが発生する可能性があります(Linuxでは、取得しますIOError: [Errno 32] Broken pipe)。

于 2010-06-08T13:09:44.213 に答える
1

プロセスとやり取りしたくない場合は、 subprocess モジュールを使用できます。

例:

tester.py

import os
import sys

for file in os.listdir('.'):
    print file

sys.stderr.write("Oh noes, a shrubbery!")
sys.stderr.flush()
sys.stderr.close()

testing.py

import subprocess

p = subprocess.Popen(['python', 'tester.py'], stdout=subprocess.PIPE,
                     stdin=subprocess.PIPE, stderr=subprocess.PIPE)

stdout, stderr = p.communicate()
print stdout, stderr

あなたの状況では、最初に stdout/stderr をファイルに書き込むだけです。サブプロセスと継続的に対話する方法を理解できませんでしたが、通信を使用してプロセスに引数を送信することもできます。

于 2010-06-08T13:36:11.717 に答える