How do I write to a Python subprocess' stdin? How do I write to a Python subprocess' stdin? python python

How do I write to a Python subprocess' stdin?


It might be better to use communicate:

from subprocess import Popen, PIPE, STDOUTp = Popen(['myapp'], stdout=PIPE, stdin=PIPE, stderr=PIPE)stdout_data = p.communicate(input='data_to_write')[0]

"Better", because of this warning:

Use communicate() rather than .stdin.write, .stdout.read or .stderr.read to avoid deadlocks due to any of the other OS pipe buffers filling up and blocking the child process.


To clarify some points:

As jro has mentioned, the right way is to use subprocess.communicate.

Yet, when feeding the stdin using subprocess.communicate with input, you need to initiate the subprocess with stdin=subprocess.PIPE according to the docs.

Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE. Similarly, to get anything other than None in the result tuple, you need to give stdout=PIPE and/or stderr=PIPE too.

Also qed has mentioned in the comments that for Python 3.4 you need to encode the string, meaning you need to pass Bytes to the input rather than a string. This is not entirely true. According to the docs, if the streams were opened in text mode, the input should be a string (source is the same page).

If streams were opened in text mode, input must be a string. Otherwise, it must be bytes.

So, if the streams were not opened explicitly in text mode, then something like below should work:

import subprocesscommand = ['myapp', '--arg1', 'value_for_arg1']p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)output = p.communicate(input='some data'.encode())[0]

I've left the stderr value above deliberately as STDOUT as an example.

That being said, sometimes you might want the output of another process rather than building it up from scratch. Let's say you want to run the equivalent of echo -n 'CATCH\nme' | grep -i catch | wc -m. This should normally return the number characters in 'CATCH' plus a newline character, which results in 6. The point of the echo here is to feed the CATCH\nme data to grep. So we can feed the data to grep with stdin in the Python subprocess chain as a variable, and then pass the stdout as a PIPE to the wc process' stdin (in the meantime, get rid of the extra newline character):

import subprocesswhat_to_catch = 'catch'what_to_feed = 'CATCH\nme'# We create the first subprocess, note that we need stdin=PIPE and stdout=PIPEp1 = subprocess.Popen(['grep', '-i', what_to_catch], stdin=subprocess.PIPE, stdout=subprocess.PIPE)# We immediately run the first subprocess and get the result# Note that we encode the data, otherwise we'd get a TypeErrorp1_out = p1.communicate(input=what_to_feed.encode())[0]# Well the result includes an '\n' at the end, # if we want to get rid of it in a VERY hacky wayp1_out = p1_out.decode().strip().encode()# We create the second subprocess, note that we need stdin=PIPEp2 = subprocess.Popen(['wc', '-m'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)# We run the second subprocess feeding it with the first subprocess' output.# We decode the output to convert to a string# We still have a '\n', so we strip that outoutput = p2.communicate(input=p1_out)[0].decode().strip()

This is somewhat different than the response here, where you pipe two processes directly without adding data directly in Python.

Hope that helps someone out.


You can provide a file-like object to the stdin argument of subprocess.call().

The documentation for the Popen object applies here.

To capture the output, you should instead use subprocess.check_output(), which takes similar arguments. From the documentation:

>>> subprocess.check_output(...     "ls non_existent_file; exit 0",...     stderr=subprocess.STDOUT,...     shell=True)'ls: non_existent_file: No such file or directory\n'