Skip to content
Happy Programming Guide
Start learning
Python

Redirect Input from a File to Standard Input in Python

Feed a file into a Python script that reads from stdin: shell redirection, pipes, sys.stdin, fileinput, and redirecting inside the program itself.

A processor chip photographed up close

The simplest way to feed a file into a script that reads standard input is shell redirection: python script.py < data.txt. Your code carries on calling input() or reading sys.stdin and never knows the difference. This guide covers that, pipes, reading stdin properly, and how to redirect from inside Python when you cannot change how the program is launched.

Shell redirection#

Terminal
python script.py < data.txt

The shell opens the file and connects it to the process’s standard input before Python starts. Nothing in your code changes.

Python
# script.py
import sys

for line in sys.stdin:
    print(line.rstrip())

This works identically on Windows in PowerShell and cmd, and on macOS and Linux.

Pipes#

Terminal
cat data.txt | python script.py
grep ERROR app.log | python count.py
python generate.py | python process.py | sort | uniq -c

A pipe connects one program’s output to the next one’s input. The practical difference from redirection is that a pipe streams — the second program can start working before the first has finished — whereas a file is simply there.

Writing a script that reads stdin and writes stdout makes it composable with every other command-line tool, which is a substantial amount of power for very little effort.

Reading standard input#

Python
import sys

# One line at a time - constant memory
for line in sys.stdin:
    process(line.rstrip("\n"))

# Everything at once
text = sys.stdin.read()

# A list of lines
lines = sys.stdin.readlines()

# A single line
first = sys.stdin.readline()

Prefer the loop. A log file of several gigabytes will exhaust memory with read() and stream comfortably with iteration.

input() also reads from stdin, so it works with redirection too:

Python
name = input()        # reads the first line of the file
age = input()         # reads the second
Python
while True:
    try:
        line = input()
    except EOFError:
        break
    process(line)

Handling both a file argument and stdin#

Well-behaved command-line tools accept either. The fileinput module does this for you:

Python
import fileinput

for line in fileinput.input():
    print(fileinput.filename(), fileinput.lineno(), line.rstrip())
Terminal
python script.py data.txt          # reads the file
python script.py a.txt b.txt       # reads both, in order
python script.py < data.txt        # reads stdin
cat data.txt | python script.py    # also stdin

Doing it by hand with argparse gives more control:

Python
import argparse
import sys

parser = argparse.ArgumentParser()
parser.add_argument("file", nargs="?", type=argparse.FileType("r"),
                    default=sys.stdin)
args = parser.parse_args()

for line in args.file:
    print(line.rstrip())

The nargs="?" makes the argument optional, and the default falls back to standard input.

Detecting where input is coming from#

Python
import sys

if sys.stdin.isatty():
    print("Type your input, then press Ctrl+D to finish:", file=sys.stderr)
else:
    pass       # input is redirected or piped

isatty() is true when a terminal is attached. Use it to show a prompt only when a person is there — and note the prompt goes to stderr, so it does not contaminate piped output.

Redirecting from inside Python#

Useful when you cannot change how the program is launched, and essential for testing:

Python
import sys

with open("data.txt") as f:
    original = sys.stdin
    sys.stdin = f
    try:
        run_the_thing()      # now reads from the file
    finally:
        sys.stdin = original

A context manager is cleaner:

Python
import sys
from contextlib import contextmanager


@contextmanager
def stdin_from(path):
    original = sys.stdin
    with open(path) as f:
        sys.stdin = f
        try:
            yield
        finally:
            sys.stdin = original


with stdin_from("data.txt"):
    run_the_thing()

For tests, feed it a string rather than a file:

Python
import io
import sys
from unittest.mock import patch


def test_reads_two_lines():
    fake = io.StringIO("Ana\n34\n")
    with patch.object(sys, "stdin", fake):
        assert read_person() == ("Ana", 34)

Pytest has this built in:

Python
def test_reads_input(monkeypatch):
    monkeypatch.setattr("sys.stdin", io.StringIO("Ana\n34\n"))
    assert read_person() == ("Ana", 34)

Feeding input to a subprocess#

Python
import subprocess

# From a string
result = subprocess.run(
    ["python", "script.py"],
    input="line one\nline two\n",
    capture_output=True,
    text=True,
)
print(result.stdout)

# From a file
with open("data.txt") as f:
    subprocess.run(["python", "script.py"], stdin=f)

Binary input#

Python
import sys

data = sys.stdin.buffer.read()        # bytes, not text
sys.stdout.buffer.write(data)

Use the .buffer attribute for images, archives and anything that is not text. Reading binary data as text corrupts it, and on Windows the line-ending translation makes that corruption worse.

Encoding#

Python
import sys

print(sys.stdin.encoding)

# Force UTF-8 regardless of the environment
sys.stdin.reconfigure(encoding="utf-8", errors="replace")

The default encoding comes from the environment, which differs between machines. Being explicit prevents a script that works locally from failing on a server with a different locale.

Questions people ask#

Why does my script hang with no input?

It is waiting for you to type. Press Ctrl+D on macOS and Linux, or Ctrl+Z then Enter on Windows, to signal end of input.

What is the difference between redirection and a pipe?

Redirection connects a file to stdin. A pipe connects another program’s output to stdin. Your code cannot tell them apart, which is the point.

Can I read stdin twice?

Not directly — it is a stream, and once consumed it is gone. Read it into a variable first if you need it more than once.

How do I read stdin without blocking?

Use select.select() on Unix, or read on a separate thread. Non-blocking stdin is awkward and cross-platform support is patchy, so consider whether the design can avoid needing it.

Where to go next#

Command line basics, including pipes and redirectionRead next

Keep reading

Keep going — pick your next guide

The fastest way to improve is to read one guide, then build the thing it describes. Start with the basics, or jump straight to a project.

Ask a question or share what worked

Your email address will not be published. Required fields are marked *