将命令管道化为Python解释器

时间:2016-07-26 22:58:10

标签: pipe subprocess python-3.5

我想通过管道逐个发送命令来控制Python解释器,e。 G。让Python解释器打印“hello”,等待3秒,然后让Python解释器打印“世界”。

为什么bash中的代码如下:

{ echo 'from sys import stdout' ; echo 'stdout.write("hello\n")' ; echo 'stdout.flush()' ; sleep 3 ; echo 'stdout.write("world\n")' ; echo 'stdout.flush()' ; } | python3.5 -u

首先等待3秒,然后打印:

hello
world

而以下代码:

{ echo 'from sys import stdout' ; echo 'stdout.write("hello\n")' ; echo 'stdout.flush()' ; sleep 3 ; echo 'stdout.write("world\n")' ; echo 'stdout.flush()' ; } | while read -r l ; do echo $l ; done

首先打印:

from sys import stdout
stdout.write("hello\n")
stdout.flush()

然后等待3秒钟,最后打印出来:

stdout.write("world\n")
stdout.flush()

最后,我想从第一个Python脚本控制第二个Python解释器,如上例所示(打印“hello”,等待3秒,打印“world”)。这是否可以使用“子进程”Python模块?

以下代码:

import logging
from select import select
from subprocess import Popen, PIPE, TimeoutExpired
from time import sleep
from threading import Thread

logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s %(message)s")
logger = logging.getLogger()

def read_stdout(proc):
    stdout_closed, stderr_closed = False, False

    while True:
        rlist, wlist, xlist = select([proc.stdout, proc.stderr], [], [], 1.2)
        if len(rlist) == 0:
            logger.debug("timeout")
            continue
        if proc.stdout in rlist:
            new_data = proc.stdout.read(1024)
            logger.debug("new_data on stdout: %r" % new_data)
            if len(new_data) == 0:
                stdout_closed = True
        if proc.stderr in rlist:
            new_data = proc.stderr.read(1024)
            logger.debug("new_data on stderr: %r" % new_data)
            if len(new_data) == 0:
                stderr_closed = True
        if stdout_closed and stderr_closed:
            break

logger.debug("start")
proc = Popen(
    #["bash", "-c", 'while read -r l ; do echo $l ; done'],
    ["python", "-u"],
    stdin=PIPE,
    stdout=PIPE,
    stderr=PIPE,
    bufsize=0)
thread = Thread(target=read_stdout, args=(proc,))
thread.start()
proc.stdin.write(b'from sys import stdout\n')
proc.stdin.write(b'stdout.write("hello\\n")\n')
proc.stdin.write(b'stdout.flush()\n')
proc.stdin.flush()
sleep(3)
proc.stdin.write(b'stdout.write("world\\n")\n')
proc.stdin.write(b'stdout.flush()\n')
proc.stdin.flush()
proc.stdin.close()
thread.join()

导致与上面的bash代码相同的问题:

当Popen()调用“python -u”时,日志输出为:

2016-07-27 00:46:05,208 start
2016-07-27 00:46:06,411 timeout
2016-07-27 00:46:07,612 timeout
2016-07-27 00:46:08,213 new_data on stdout: b'hello\nworld\n'
2016-07-27 00:46:08,216 new_data on stdout: b''
2016-07-27 00:46:08,216 new_data on stderr: b''

而当Popen()调用“bash -c”而读取-r l;执行echo $ l; done'“时,则日志输出为:

2016-07-27 00:48:37,237 start
2016-07-27 00:48:37,239 new_data on stdout: b'from sys import stdout\n'
2016-07-27 00:48:37,239 new_data on stdout: b'stdout.write("hello\\n")\nstdout.flush()\n'
2016-07-27 00:48:38,440 timeout
2016-07-27 00:48:39,642 timeout
2016-07-27 00:48:40,242 new_data on stdout: b'stdout.write("world\\n")\n'
2016-07-27 00:48:40,242 new_data on stdout: b'stdout.flush()\n'
2016-07-27 00:48:40,242 new_data on stderr: b''
2016-07-27 00:48:40,242 new_data on stdout: b''
2016-07-27 00:48:40,242 new_data on stderr: b''

Python解释器不立即执行发送给它的命令的原因是什么?有可能以某种方式使用“子进程”模块实现这一点吗? (我假设“pexpect”将解决问题,但我想了解“subprocess”是否或为什么不能解决它。)

1 个答案:

答案 0 :(得分:0)

我在" man python3"中找到了以下关于观察到的行为的解释:

在非交互模式下,整个输入在执行之前进行解析。