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 脚本中记录屏幕上显示的所有内容。但我似乎无法使这部分起作用。

我已经尝试了使用子流程的各种方法。PIPE,但这通常会破坏交互性,例如不输出提示字符串。

我也尝试了各种方法来直接更改sys.stdout的行为,但是由于子进程直接写入sys.stdout.fileno(),这一切都无济于事。

>由于缓冲问题以及某些程序直接从终端写入/读取(例如,检索密码)的事实,Popen可能不太适合交互式程序。参见问:为什么不直接使用管道(popen())?。

如果要模拟script实用程序,则可以使用pty.spawn(),请参阅从 Python 子进程复制终端输出或日志语法错误和 python 子进程未捕获的异常中的代码示例,并将它们打印到终端:

#!/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 子流程中的teed_call()将孩子的输出获取到文件和终端?

这应该有效

import subprocess
f = open('file.txt','w')
cmd = ['echo','hello','world']
subprocess.call(cmd, stdout=f)

最新更新