Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a string into subprocess.Popen (using the stdin argument)?

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?

like image 891
Daryl Spitzer Avatar asked Oct 02 '08 17:10

Daryl Spitzer


People also ask

How do you pass arguments in subprocess Popen?

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.

How do I write to a Python subprocess stdin?

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.

What is Popen in subprocess?

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.


1 Answers

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 # ->  
like image 82
jfs Avatar answered Sep 20 '22 22:09

jfs