如何在Python中使用子进程模块编写stdin之前打印stdout

时间:2012-07-23 04:25:45

标签: python subprocess

我正在编写一个脚本,在外部系统命令中有时可能需要用户输入。我无法妥善处理。我尝试过使用os.popen4和子进程模块但无法实现所需的行为。

下面提到的示例将使用“cp”命令显示此问题。 (“cp”命令用于显示此问题,我正在调用一些不同的exe,在某些情况下可能会同样提示用户响应)。在此示例中,磁盘上存在两个文件,当用户尝试将file1复制到file2时,会出现一个conformer消息。

proc = subprocess.Popen("cp -i a.txt b.txt", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,)
stdout_val, stderr_val = proc.communicate()
print stdout_val
  
    

b.txt?

  
proc.communicate("y")

现在在这个例子中,如果我只读取stdout / stderr并打印它,稍后如果我尝试根据用户的输入写“y”或“n”,我得到一个错误,即通道关闭。

有人可以帮我在python中实现这个行为,这样我可以先打印stdout,然后再接受用户输入并写入stdin。

我从Non-blocking read on a subprocess.PIPE in python找到了另一种解决方案(线程),不确定它是否会有所帮助。但它似乎是来自cp命令的打印问题,我修改了代码但不确定如何在线程代码中编写。

import sys
from subprocess import PIPE, Popen
from threading import Thread
try:
    from Queue import Queue, Empty
except ImportError:
    from queue import Queue, Empty

ON_POSIX = 'posix' in sys.builtin_module_names

def enqueue_output(out, queue):
    for line in iter(out.readline, b''):
        queue.put(line)
    out.close()

 p = Popen(['cp', '-i', 'a.txt', 'b.txt'],stdin=PIPE, stdout=PIPE, bufsize=1, close_fds=ON_POSIX)
q = Queue()
t = Thread(target=enqueue_output, args=(p.stdout, q))
t.start()

try:
    line = q.get_nowait()
except Empty:
    print('no output yet')
else:
   pass

2 个答案:

答案 0 :(得分:1)

Popen.communicate将运行子进程完成,因此您不能多次调用它。您可以直接使用stdin and stdout attributes,虽然这样做有风险,因为如果进程使用块缓冲或缓冲区填满,您可能会死锁:

stdout_val = proc.stdout.readline()
print stdout_val
proc.stdin.write('y\n')

由于存在死锁的风险,并且如果进程使用块缓冲,这可能不起作用,您最好考虑使用pexpect package

答案 1 :(得分:0)

我对这个问题没有技术答案。更多只是一个解决方案。它与进程等待输入的方式有关,一旦与进程通信,None输入就足以关闭进程。

对于cp示例,您可以使用proc.poll()立即检查返回代码。如果返回值为None,您可能会认为它正在尝试等待输入并可以向您的用户提问。然后,您可以通过proc.communicate(response)将响应传递给流程。然后它将传递该值并继续该过程。

也许其他人可以使用更为技术性的理由来填充为什么带有None值的初始communicate会关闭该过程。