我有一个Python脚本需要通过命令行与用户交互,同时记录输出的内容。
我目前有这个:
# lots of code
popen = subprocess.Popen(
args,
shell=True,
stdin=sys.stdin,
stdout=sys.stdout,
stderr=sys.stdout,
executable='/bin/bash')
popen.communicate()
# more code
这将执行shell命令(例如adduser newuser02),就像在终端中键入它一样,包括交互行为。这很好。
现在,我想从Python脚本中记录屏幕上显示的所有内容。但我似乎无法使那部分工作。
我尝试了各种使用subprocess.PIPE的方法,但这通常会弄乱交互性,就像不输出提示字符串一样。
我也尝试了各种方法来直接更改sys.stdout的行为,但是当子进程直接写入sys.stdout.fileno()时,这一切都无济于事。
答案 0 :(得分:2)
Popen
可能不太适合由于buffering issues而导致的交互式程序,并且由于some programs write/read directly from a terminal例如要检索密码。请参阅Q: Why not just use a pipe (popen())?。
如果您想模仿script
utility,那么您可以使用pty.spawn()
,请参阅Duplicating terminal output from a Python subprocess或log syntax errors and uncaught exceptions for a python subprocess and print them to the terminal中的代码示例:
#!/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)
或者您可以使用pexpect
获得更大的灵活性:
import sys
import pexpect # $ pip install pexpect
with open('log', 'ab') as fout:
p = pexpect.spawn("python test.py")
p.logfile = fout # or .logfile_read
p.interact()
如果您的子进程没有缓冲其输出(或者它不会干扰交互性)并且它将其输出打印到其stdout或stderr,那么您可以尝试subprocess
:
#!/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()
要分别阅读stdout / stderr,您可以使用Python subprocess get children's output to file and terminal?中的teed_call()
答案 1 :(得分:0)
这应该有效
import subprocess
f = open('file.txt','w')
cmd = ['echo','hello','world']
subprocess.call(cmd, stdout=f)