How do I pass a string into subprocess.Popen (using the stdin argument)?
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
# ->
How do I pass a string in to subprocess.run using stdin in Python 3
Simplest possible example, send foo
to cat
and let it print to the screen.
import subprocess
subprocess.run(['cat'],input=b'foo\n')
Notice that you send binary data and the carriage return.
How to use STDIN from subprocess.Popen
I was able to solve my problem by using Popen.communicate()
So some kind of pseudo code:
proc = subprocess.Popen(…)
proc.communicate(input="my_input_via_stdin")
Supply stdin input to subprocess.Popen() after execution of the process had begun ( and before it had finished )
First I think readline()
is problematic here, unless the prompt from the program ends in a newline(): the program writes a prompt and is waiting for an answer while readline()
is waiting for an end-of-line. I think you're going to have to use read()
instead and do things a bit more low level.
To actually send something to the program, I think you can just write to process.stdin
.
Have a look at pexpect (https://pexpect.readthedocs.io). I'm not sure it fits your use case, but if it does it can make life easier so it's worth the effort to find out.
One other thing to consider: many commands have an option to make it work without extra prompts, to prevent the problem you're having when run from another program. If that's the case with the program you're using, that would be by far the easiest solution.
How do I pass a string into subprocess.Popen in Python 2?
Have you tried to feed your string to communicate as a string?
Popen.communicate(input=my_input)
It works like this:
p = subprocess.Popen(["head", "-n", "1"], stdin=subprocess.PIPE)
p.communicate('first\nsecond')
output:
first
I forgot to set stdin to subprocess.PIPE when I tried it at first.
How do I write to a Python subprocess' stdin?
It might be better to use communicate
:
from subprocess import Popen, PIPE, STDOUT
p = 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.
Send a string as a parameter in python subprocess
The problem in your code is that you are calling subprocess.Popen
in the wrong way. In order to achieve what you want, as the documentation states, Popen
should be called with a list of strings containing the "executable" and all the other arguments separately. More precisely, in your case it should be:
p = subprocess.Popen([filepath, os.path.abspath('.\\file.txt')], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
As a side note, you should/would use .communicate(...)
only when the "executable" launched "asks" for input (stdin).
How to pass subprocess control to regular stdin after using a pipe?
Unfortunately, there is no standard way to splice your own stdin to some other process's stdin for the duration of that process, other than to read from your own stdin and write to that process, once you have chosen to write to that process in the first place.
That is, you can do this:
proc = subprocess.Popen(...) # no stdin=
and the process will inherit your stdin; or you can do this:
proc = subprocess.Popen(..., stdin=subprocess.PIPE, ...)
and then you supply the stdin to that process. But once you have chosen to supply any of its stdin, you supply all of its stdin, even if that means you have to read your own stdin.
Linux offers a splice
system call (documentation at man7.org, documentation at linux.die.net, Wikipedia, linux pipe data from file descriptor into a fifo) but your best bet is probably a background thread to copy the data.
Related Topics
How to Improve Performance of This Code
Understanding the "Is" Operator
Split String With Multiple Delimiters in Python
"Unicode Error "Unicodeescape" Codec Can't Decode Bytes... Cannot Open Text Files in Python 3
How Does Assignment Work With List Slices
Why Should Exec() and Eval() Be Avoided
Concatenate Strings from Several Rows Using Pandas Groupby
How to Have One Colorbar For All Subplots
Why Is "Except: Pass" a Bad Programming Practice
What Are the Advantages of Numpy Over Regular Python Lists
Meaning of @Classmethod and @Staticmethod For Beginner
How to Expand the Output Display to See More Columns of a Pandas Dataframe
How to Use a Decimal Step Value For Range()
How to Use Glob() to Find Files Recursively
Can a Variable Number of Arguments Be Passed to a Function
Pip Install Failing With: Oserror: [Errno 13] Permission Denied on Directory