Many tools (jq, sort, grep, compilers) read from stdin, and pipelines are common in scripts.
input= sends data to the child's standard input and closes it, so the program sees end-of-file. Use a str with text=True, or bytes otherwise.
r = subprocess.run(["sort"], input="b\na\n", capture_output=True, text=True)If you don't pass input or stdin, the child inherits your stdin. A command that unexpectedly waits for input (a password prompt, cat with no file) then hangs your script. In scripts and services, pass stdin=subprocess.DEVNULL so such reads see EOF immediately.
stdin= also accepts an open file, so stdin=open("data.csv") streams a file without loading it into memory.
To build a pipeline like ps aux | grep python without shell=True, the simplest way is to pass the first command's output as the second's input:
ps = subprocess.run(["ps", "aux"], capture_output=True, text=True, check=True)
hits = subprocess.run(["grep", "python"], input=ps.stdout, capture_output=True, text=True)This holds the intermediate data in memory, which is fine for most outputs. For large streams, connect processes directly with Popen (a later lesson). Often the simplest pipeline is no pipeline at all: filter the output in Python.
Example
import subprocess, sys
r = subprocess.run(["sort", "-r"], input="apple\ncherry\nbanana\n",
capture_output=True, text=True, check=True)
print(r.stdout.split()) # ['cherry', 'banana', 'apple']
words = subprocess.run(["printf", "a b\nc\n"], capture_output=True, text=True).stdout
count = subprocess.run(["wc", "-w"], input=words, capture_output=True, text=True)
print(count.stdout.strip()) # 3
r = subprocess.run([sys.executable, "-c", "print(repr(input('name? ')))"],
stdin=subprocess.DEVNULL, capture_output=True, text=True)
print(r.stderr.strip().splitlines()[-1]) # EOFError: EOF when reading a lineRemember
- input= writes data to stdin and closes it
- stdin=DEVNULL prevents hangs on unexpected prompts
- Chain commands by passing one result's stdout as the next input
Watch out for
- Letting a child inherit stdin in a cron job or service, where a prompt then blocks forever.