Python脚本和linux shell之间的交互 [英] Interaction between Python script and linux shell

查看:631
本文介绍了Python脚本和linux shell之间的交互的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Python脚本,需要在记录输出内容的同时通过命令行与用户交互.

I have a Python script that needs to interact with the user via the command line, while logging whatever is output.

我目前有这个:

# 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),就像在终端中键入它一样,包括交互行为.很好.

This executes a shell command (e.g. adduser newuser02) just as it would when typing it into a terminal, including interactive behavior. This is good.

现在,我想从Python脚本中记录屏幕上出现的所有内容.但我似乎无法使该部分正常工作.

Now, I want to log, from within the Python script, everything that appears on the screen. But I can't seem to make that part work.

我尝试了各种使用subprocess.PIPE的方法,但这通常会搞乱交互性,例如不输出提示字符串.

I've tried various ways of using subprocess.PIPE, but this usually messes up the interactivity, like not outputting prompt strings.

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

I've also tried various ways to directly change the behavior of sys.stdout, but as subprocess writes to sys.stdout.fileno() directly, this was all to no avail.

推荐答案

Popen由于缓冲问题,并且由于某些程序直接从终端写入/读取这一事实,例如检索一个密码.请参见问:为什么不仅仅使用管道(popen())?.

Popen might not be very suitable for interactive programs due to buffering issues and due to the fact that some programs write/read directly from a terminal e.g., to retrieve a password. See Q: Why not just use a pipe (popen())?.

如果要模拟 script实用程序,则可以使用 pty.spawn() ,请参见日志语法python子进程的错误和未捕获的异常,并将它们打印到终端:

If you want to emulate script utility then you could use pty.spawn(), see the code example in Duplicating terminal output from a Python subprocess or in 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 以获得更大的灵活性:

Or you could use pexpect for more flexibility:

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,则可以尝试

If your child process doesn't buffer its output (or it doesn't interfere with the interactivity) and it prints its output to its stdout or stderr then you could try 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()将孩子的输出输出到文件和终端?

To read both stdout/stderr separately, you could use teed_call() from Python subprocess get children's output to file and terminal?

这篇关于Python脚本和linux shell之间的交互的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆