リンクしたティーベースの回答は、タスクにはあまり適していません。バッファリングを無効にするオプションを使用して「raw_input()
プロンプト」の問題を修正できますが:-u
errf = open('err.txt', 'wb') # any object with .write() method
rc = call([sys.executable, '-u', 'test.py'], stderr=errf,
bufsize=0, close_fds=True)
errf.close()
pexpect
より適切なソリューションは、 orpty
に基づいている可能性があります。
ロガー プログラムの実行は、ユーザーが通常どおり python test.py を実行したように見える必要があります。
#!/usr/bin/env python
import sys
import pexpect
with open('log', 'ab') as fout:
p = pexpect.spawn("python test.py")
p.logfile = fout
p.interact()
インストールする必要はありませんpexpect
。これは純粋な Python であり、コードと一緒に配置できます。
これはティーベースのアナログです(test.py
非インタラクティブに実行されます):
#!/usr/bin/env python
import sys
from subprocess import Popen, PIPE, STDOUT
from threading import Thread
def tee(infile, *files):
"""Print `infile` to `files` in a separate thread."""
def fanout(infile, *files):
flushable = [f for f in files if hasattr(f, 'flush')]
for c in iter(lambda: infile.read(1), ''):
for f in files:
f.write(c)
for f in flushable:
f.flush()
infile.close()
t = Thread(target=fanout, args=(infile,)+files)
t.daemon = True
t.start()
return t
def call(cmd_args, **kwargs):
stdout, stderr = [kwargs.pop(s, None) for s in 'stdout', 'stderr']
p = Popen(cmd_args,
stdout=None if stdout is None else PIPE,
stderr=None if stderr is None else (
STDOUT if stderr is STDOUT else PIPE),
**kwargs)
threads = []
if stdout is not None:
threads.append(tee(p.stdout, stdout, sys.stdout))
if stderr is not None and stderr is not STDOUT:
threads.append(tee(p.stderr, stderr, sys.stderr))
for t in threads: t.join() # wait for IO completion
return p.wait()
with open('log','ab') as file:
rc = call([sys.executable, '-u', 'test.py'], stdout=file, stderr=STDOUT,
bufsize=0, close_fds=True)
がプロンプトを出力する可能性がある場所raw_input()
が不明であるため、stdout/stderr をマージする必要があります。getpass.getpass()
この場合、スレッドも必要ありません。
#!/usr/bin/env python
import sys
from subprocess import Popen, PIPE, STDOUT
with open('log','ab') as file:
p = Popen([sys.executable, '-u', 'test.py'],
stdout=PIPE, stderr=STDOUT,
close_fds=True,
bufsize=0)
for c in iter(lambda: p.stdout.read(1), ''):
for f in [sys.stdout, file]:
f.write(c)
f.flush()
p.stdout.close()
rc = p.wait()
注: 最後の例と tee ベースのソリューションはgetpass.getpass()
プロンプトをキャプチャしませんが、pexpect
andpty
ベースのソリューションは次のことを行います。
#!/usr/bin/env python
import os
import pty
import sys
with open('log', 'ab') as file:
def read(fd):
data = os.read(fd, 1024)
file.write(data)
file.flush()
return data
pty.spawn([sys.executable, "test.py"], read)
Macで動作するかどうかはわかりませんpty.spawn()
。