Python subprocess communicate kills my process

2019-07-21 17:31发布

问题:

Why does communicate kill my process? I want an interactive process but communicate does something so that I cannot take raw_input any more in my process.

from sys import stdin 
from threading import Thread
from time import sleep

if __name__ == '__main__':
    print("Still Running\n")
    x = raw_input()    
    i = 0
    while ('n' not in x ) :
        print("Still Running " + str(i) + " \r\n")
        x = raw_input()
        i += 1

    print("quit")



print(aSubProc.theProcess.communicate('y'))
print(aSubProc.theProcess.communicate('y'))

exception!

self.stdin.write(input)
ValueError: I/O operation on closed file

回答1:

communicate and wait methods of Popen objects, close the PIPE after the process returns. If you want stay in communication with the process try something like this:

import subprocess
proc = subprocess.Popen("some_process", stdout=subprocess.PIPE, stdin=subprocess.PIPE)
proc.stdin.write("input")
proc.stdout.readline()


回答2:

Why does communicate kill my process?

From the docs for Popen.communicate(input=None, timeout=None):

Interact with process: Send data to stdin. Read data from stdout and
stderr, until end-of-file is reached. Wait for process to terminate. emphasize mine

You may call .communicate() only once. It means that you should provide all input at once:

#!/usr/bin/env python
import os
import sys
from subprocess import Popen, PIPE

p = Popen([sys.executable, 'child.py'], stdin=PIPE, stdout=PIPE)
print p.communicate(os.linesep.join('yyn'))[0]

Output

Still Running

Still Running 0 

Still Running 1 

quit

Notice the doubled newlines: one from '\r\n' and another from print statement itself in your script for the child process.

Output shows that the child process received three input lines successfully ('y', 'y', and 'n').

Here's a similar code using subprocess.check_output()'s input parameter from Python3.4:

#!/usr/bin/env python3.4
import os
import sys
from subprocess import check_output

output = check_output(['python2', 'child.py'], universal_newlines=True,
                      input='\n'.join('yyn'))
print(output, end='')

It produces the same output.


If you want to provide a different input depending on responses from the child processes then use pexpect module or its analogs to avoid issues mentioned in Why not just use a pipe (popen())?