コンソールから非表示にせずにコマンドの出力をファイルに保存できるPythonソリューションを探しています。
参考までに、私は tee (Unixコマンドラインユーティリティとして)について質問しており、Python intertoolsモジュールからの同じ名前の関数については質問していません。
tee
を呼び出さない、Windowsでは使用できません)stderr
とstdout
の両方で機能するstderr = subprocess.STDOUT
動作しないでしょう。ここに私がこれまでに見つけたいくつかの不完全な解決策があります:
図http://blog.i18n.ro/wp-content/uploads/2010/06/Drawing_tee_py.png
#!/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--
予想される出力は、行が順序付けられることでした。注釈:1つのPIPEのみを使用するようにPopenを変更することは許可されていません。現実には、私はstderrとstdoutで異なることをしたいからです。
また、2番目のケースでもリアルタイムのアウトを取得することはできませんでした。実際には、プロセスが終了したときにすべての結果を受け取りました。デフォルトでは、Popenはバッファを使用しません(bufsize = 0)。
これはかなり古い投稿ですが、誰かがこれを行う方法をまだ探している場合に備えて:
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)
最後に、私はtee()
コマンドをPython自分で実装する必要がありました。
ここから入手できます http://github.com/pycontribs/tendo/blob/master/tendo/tee.py
現在、次のようなことができます。
tee("python --v") # works just like os.system()
tee("python --v", "log.txt") # file names
tee("python --v", file_handle)
import logging
tee("python --v", logging.info) # receive a method
現在の唯一の制限は、stderr
とstdout
を区別できないことです。つまり、両方をマージします。
これは 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
の部分については、サブプロセスのstdin
、stdout
およびstderr
をstdin
、stdout
、stderr
およびファイルシンクですが、これを実行できることはわかっています。
_import subprocess
callee = subprocess.Popen( ["python", "-i"],
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
)
_
これで、通常のファイルと同様に _callee.stdin
_ 、 _callee.stdout
_ および _callee.stderr
_ にアクセスできるため、上記の「ソリューション」が機能します。 _callee.returncode
_ を取得するには、 callee.poll()
を追加で呼び出す必要があります。
_callee.stdin
_への書き込みには注意してください。そのときにプロセスが終了した場合、エラーが発生する可能性があります(Linuxでは_IOError: [Errno 32] Broken pipe
_が表示されます)。
python subprocess.PIPEに関連する)に微妙な問題/バグがあります: http://bugs.python.org/issue1652
どうやらこれはpython3 +で修正されましたが、python 2.7以前では修正されていません。そのためには、code.google.com/p/python-subprocess32 /を使用する必要があります。
プロセスとやり取りしたくない場合は、サブプロセスモジュールを使用できます。
例:
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を最初にファイルに書き込むことができます。通信を使用してプロセスに引数を送信することもできますが、サブプロセスと継続的に対話する方法を理解することはできませんでした。
これはそれができる方法です
import sys
from subprocess import Popen, PIPE
with open('log.log', 'w') as log:
proc = Popen(["ping", "google.com"], stdout=PIPE, encoding='utf-8')
while proc.poll() is None:
text = proc.stdout.readline()
log.write(text)
sys.stdout.write(text)
Pythonでシェルコマンドをラップするものを書きました。
主な利点:
主な欠点:
ソース: https://Gist.github.com/AndrewHoos/9f03c74988469b517a7a
これを試して :
import sys
class tee-function :
def __init__(self, _var1, _var2) :
self.var1 = _var1
self.var2 = _var2
def __del__(self) :
if self.var1 != sys.stdout and self.var1 != sys.stderr :
self.var1.close()
if self.var2 != sys.stdout and self.var2 != sys.stderr :
self.var2.close()
def write(self, text) :
self.var1.write(text)
self.var2.write(text)
def flush(self) :
self.var1.flush()
self.var2.flush()
stderrsav = sys.stderr
out = open(log, "w")
sys.stderr = tee-function(stderrsav, out)
私のソリューションはエレガントではありませんが、機能します。
Powershellを使用して、WinOSで「Tee」にアクセスできます。
import subprocess
import sys
cmd = ['powershell', 'ping', 'google.com', '|', 'tee', '-a', 'log.txt']
if 'darwin' in sys.platform:
cmd.remove('powershell')
p = subprocess.Popen(cmd)
p.wait()