If I do the following:
import subprocess from cStringIO import StringIO subprocess.Popen(['grep','f'],stdout=subprocess.PIPE,stdin=StringIO('one\ntwo\nthree\nfour\nfive\nsix\n')).communicate()[0]
I get:
Traceback (most recent call last): File "<stdin>", line 1, in ? File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 533, in __init__ (p2cread, p2cwrite, File "/build/toolchain/mac32/python-2.4.3/lib/python2.4/subprocess.py", line 830, in _get_handles p2cread = stdin.fileno() AttributeError: 'cStringIO.StringI' object has no attribute 'fileno'
Apparently a cStringIO.StringIO object doesn't quack close enough to a file duck to suit subprocess.Popen. How do I work around this?
To pass variables to Python subprocess. Popen, we cann Popen with a list that has the variables we want to include. to call Popen with the command list that has some static and dynamic command arguments.
To write to a Python subprocess' stdin, we can use the communicate method. to call Popen with the command we want to run in a list. And we set stdout , stdin , and stderr all to PIPE to pipe them to their default locations.
The subprocess module defines one class, Popen and a few wrapper functions that use that class. The constructor for Popen takes arguments to set up the new process so the parent can communicate with it via pipes. It provides all of the functionality of the other modules and functions it replaces, and more.
Popen.communicate()
documentation:
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.
Replacing os.popen*
pipe = os.popen(cmd, 'w', bufsize) # ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
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.
So your example could be written as follows:
from subprocess import Popen, PIPE, STDOUT p = Popen(['grep', 'f'], stdout=PIPE, stdin=PIPE, stderr=STDOUT) grep_stdout = p.communicate(input=b'one\ntwo\nthree\nfour\nfive\nsix\n')[0] print(grep_stdout.decode()) # -> four # -> five # ->
On Python 3.5+ (3.6+ for encoding
), you could use subprocess.run
, to pass input as a string to an external command and get its exit status, and its output as a string back in one call:
#!/usr/bin/env python3 from subprocess import run, PIPE p = run(['grep', 'f'], stdout=PIPE, input='one\ntwo\nthree\nfour\nfive\nsix\n', encoding='ascii') print(p.returncode) # -> 0 print(p.stdout) # -> four # -> five # ->
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With