Python脚本和linux shell之间的交互

我有一个
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()时,这一切都无济于事.

最佳答案 由于
buffering issues和由于
some programs write/read directly from a terminal例如检索密码这一事实,Popen可能不太适合于交互式程序.见
Q: Why not just use a pipe (popen())?.

如果要模拟script utility,则可以使用pty.spawn(),请参阅Duplicating terminal output from a Python subprocesslog 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()

点赞