The following should just work.

import sys
for line in sys.stdin:
    # whatever

Rationale:

The code will iterate over lines in stdin as they come in. If the stream is still open, but there isn't a complete line then the loop will hang until either a newline character is encountered (and the whole line returned) or the stream is closed (and the whatever is left in the buffer is returned).

Once the stream has been closed, no more data can be written to or read from stdin. Period.

The reason that your code was overloading your cpu is that once the stdin has been closed any subsequent attempts to iterate over stdin will return immediately without doing anything. In essence your code was equivalent to the following.

for line in sys.stdin:
    # do something

while 1:
    pass # infinite loop, very CPU intensive

Maybe it would be useful if you posted how you were writing data to stdin.

EDIT:

Python will (for the purposes of for loops, iterators and readlines() consider a stream closed when it encounters an EOF character. You can ask python to read more data after this, but you cannot use any of the previous methods. The python man page recommends using

import sys
while True:
    line = sys.stdin.readline()
    # do something with line

When an EOF character is encountered readline will return an empty string. The next call to readline will function as normal if the stream is still open. You can test this out yourself by running the command in a terminal. Pressing ctrl+D will cause a terminal to write the EOF character to stdin. This will cause the first program in this post to terminate, but the last program will continue to read data until the stream is actually closed. The last program should not 100% your CPU as readline will wait until there is data to return rather than returning an empty string.

I only have the problem of a busy loop when I try readline from an actual file. But when reading from stdin, readline happily blocks.

Answer from Dunes on Stack Overflow
Top answer
1 of 9
22

The following should just work.

import sys
for line in sys.stdin:
    # whatever

Rationale:

The code will iterate over lines in stdin as they come in. If the stream is still open, but there isn't a complete line then the loop will hang until either a newline character is encountered (and the whole line returned) or the stream is closed (and the whatever is left in the buffer is returned).

Once the stream has been closed, no more data can be written to or read from stdin. Period.

The reason that your code was overloading your cpu is that once the stdin has been closed any subsequent attempts to iterate over stdin will return immediately without doing anything. In essence your code was equivalent to the following.

for line in sys.stdin:
    # do something

while 1:
    pass # infinite loop, very CPU intensive

Maybe it would be useful if you posted how you were writing data to stdin.

EDIT:

Python will (for the purposes of for loops, iterators and readlines() consider a stream closed when it encounters an EOF character. You can ask python to read more data after this, but you cannot use any of the previous methods. The python man page recommends using

import sys
while True:
    line = sys.stdin.readline()
    # do something with line

When an EOF character is encountered readline will return an empty string. The next call to readline will function as normal if the stream is still open. You can test this out yourself by running the command in a terminal. Pressing ctrl+D will cause a terminal to write the EOF character to stdin. This will cause the first program in this post to terminate, but the last program will continue to read data until the stream is actually closed. The last program should not 100% your CPU as readline will wait until there is data to return rather than returning an empty string.

I only have the problem of a busy loop when I try readline from an actual file. But when reading from stdin, readline happily blocks.

2 of 9
4

This actually works flawlessly (i.e. no runnaway CPU) - when you call the script from the shell, like so:

tail -f input-file | yourscript.py

Obviously, that is not ideal - since you then have to write all relevant stdout to that file -

but it works without a lot of overhead! Namely because of using readline() - I think:

while 1:
        line = sys.stdin.readline()

It will actually stop and wait at that line until it gets more input.

Hope this helps someone!

🌐
Reddit
reddit.com › r/learnpython › sys.stdin.read() waits for input after eof?
r/learnpython on Reddit: sys.stdin.read() waits for input after EOF?
December 7, 2021 -

Hi,

I'm fairly new to python, but not to programming as a whole. I'm trying to read input via standard in:

numList = list(map(int, sys.stdin.read().split()))

Basically I'm expecting a long string of integers that i want to store as a list. This line, however, doesn't work, as the terminal keeps waiting for input endlessly. Isn't stdin.read() supposed to read until EOF? This exact line has worked for me in the past, until I had to reinstall windows, whereafter the problem started occuring. Any tips as of how to fix this would be greatly appreciated! Perhaps it's some vs code extension that is missing? Though it seems unlikely.

Top answer
1 of 3
1
Did you re-install the same version of windows? If not, might windows have changed how an EOF is generated in the terminal? (I've had the good fortune of not having to use windows for a couple years now, so I'm rusty.) Did you change the code? Perhaps now you're calling this line in a loop? If you suspect that problem is with windows, you might try writing a test program in a language you're more familiar with that does a read and see if it receives the EOF.
2 of 3
1
What's EOF in this context? I don't know how it works on Windows, but on Linux, the idea is more or less this: read() will read until stdin file descriptor is closed. Closing a file descriptor sends a signal to the reading process, which, in this case, will be handled by Python, and it will stop reading (typically, this will result in an error though, eg. KeyboardInterrupt). EOF is usually something artificial. Like when the language tries to make it easier for the programmer to deal with how file streams or socket streams are handled. But outside of EOFError, python doesn't really have anything built-in that would be called that. Unfortunately, the way interactive applications are used, they typically go through a terminal, where terminal controls how much input is sent. Terminals usually work in line input mode. I.e. they will only send information after the whole line was inputted (i.e. you must press "Enter" to send anything to Python). This also means that if your program wants to read arbitrary long input, which not necessarily ends in an endline... it's going to block forever.
Discussions

Python async: Waiting for stdin input while doing other stuff - Stack Overflow
I'm trying to create a WebSocket command line client that waits for messages from a WebSocket server but waits for user input at the same time. Regularly polling multiple online sources every second More on stackoverflow.com
🌐 stackoverflow.com
Should ast wait for stdin if we didn't pass anthing in `python3 -m ast`
why should it wait? ▶ ./python -m ast Namespace(infile= it’s stuck here, I guess we can wait for user input and can signal(signal of pressing enter key) the script to continue but should we make it stuck? is this an intended behavior? More on discuss.python.org
🌐 discuss.python.org
0
0
July 7, 2023
io - Python reading from stdin while doing other tasks - Software Engineering Stack Exchange
It will use those messages to determine if an IP address should be banned or not. The problem I have is that after x seconds the ban should be removed, but if I won’t get any input from stdin, my program will just block waiting for it. More on softwareengineering.stackexchange.com
🌐 softwareengineering.stackexchange.com
May 9, 2013
python - How do I wait for a pressed key? - Stack Overflow
This is similar to code I've seen elsewhere (in the old python FAQs for instance) but that code spins in a tight loop where this code doesn't and there are lots of odd corner cases that code doesn't account for that this code does. def read_single_keypress(): """Waits for a single keypress on stdin. More on stackoverflow.com
🌐 stackoverflow.com
🌐
Python
docs.python.org › 3 › library › subprocess.html
subprocess — Subprocess management
When the timeout parameter is not None, then (on POSIX) the function is implemented using a busy loop (non-blocking call and short sleeps). Use the asyncio module for an asynchronous wait: see asyncio.create_subprocess_exec. Changed in version 3.3: timeout was added. ... Interact with process: Send data to stdin.
🌐
repolinux
repolinux.wordpress.com › 2012 › 10 › 09 › non-blocking-read-from-stdin-in-python
Non-blocking read from stdin in python | repolinux
May 30, 2022 - Treat available input immediately, but do something else if idle.""" import sys import select import time # files monitored for input read_list = [sys.stdin] # select() should wait for this many seconds for input. # A smaller number means more cpu usage, but a greater one # means a more noticeable delay between input becoming # available and the program starting to work on it.
🌐
Python.org
discuss.python.org › python help
Should ast wait for stdin if we didn't pass anthing in `python3 -m ast` - Python Help - Discussions on Python.org
July 7, 2023 - why should it wait? ▶ ./python -m ast Namespace(infile=<_io.BufferedReader name='<stdin>'>, mode='exec', no_type_comments=True, include_attributes=False, indent=3) <_io.BufferedReader name='<stdin>'> it’s st…
🌐
Benjdd
benjdd.com › courses › cs250 › spring-2017 › lectures › python-read-stdin.html
CSc 250: Lecture Notes: reading from stdin
For this, we will use a function in the sys module, which is built-in to python. So first, we import it: import sys · The function that we need is called readline(), and it can be called via: sys.stdin.readline() When this is executed, it tells the python program to wait for a full line of text input coming from standard input.
Find elsewhere
🌐
Python
docs.python.org › 3 › library › asyncio-subprocess.html
Subprocesses — Python 3.14.3 documentation
February 23, 2026 - This method can deadlock when using stdout=PIPE or stderr=PIPE and the child process generates so much output that it blocks waiting for the OS pipe buffer to accept more data. Use the communicate() method when using pipes to avoid this condition. ... The optional input argument is the data (bytes object) that will be sent to the child process. Return a tuple (stdout_data, stderr_data). If either BrokenPipeError or ConnectionResetError exception is raised when writing input into stdin, the exception is ignored.
Top answer
1 of 1
6

Read the documentation carefully (emphasis mine):

Popen.communicate(input=None)

Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.

communicate() returns a tuple (stdoutdata, stderrdata).

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.

So, you're sending nothing to the process, and reading all of stdout at once.


In your case, you don't really need to wait for the prompt to send data to the process because streams work asynchronously: the process will get your input only when it tries to read its STDIN:

In [10]: p=subprocess.Popen(("bash", "-c","echo -n 'prompt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)

In [11]: p.communicate('foobar')
Out[11]: ('prompt: foobar\n', None)

If you insist on waiting for the prompt for whatever reason (e.g. your process checks the input before the prompt, too, expecting something else), you need to read STDOUT manually and be VERY careful how much you read: since Python's file.read is blocking, a simple read() will deadlock because it waits for EOF and the subprocess doesn't close STDOUT -- thus doesn't produce EOF -- until it get input from you. If the input or output length is likely to go over stdio's buffer length (unlikely in your specific case), you also need to do stdout reading and stdin writing in separate threads.

Here's an example using pexpect that takes care of that for you (I'm using pexpect.fdexpect instead of pexpect.spawn suggested in the doc 'cuz it works on all platforms):

In [1]: import pexpect.fdpexpect

In [8]: p=subprocess.Popen(("bash", "-c","echo -n 'prom'; sleep 5; echo 'pt: '; read -r data; echo $data"),stdin=subprocess.PIPE,stdout=subprocess.PIPE)

In [10]: o=pexpect.fdpexpect.fdspawn(p.stdout.fileno())

In [12]: o.expect("prompt: ")
Out[12]: 0

In [16]: p.stdin.write("foobar")    #you can communicate() here, it does the same as
                                    # these 3 steps plus protects from deadlock
In [17]: p.stdin.close()
In [18]: p.stdout.read()
Out[18]: 'foobar\n'
🌐
Runebook.dev
runebook.dev › en › docs › python › library › asyncio-subprocess › asyncio.subprocess.Process.stdin
python - Async Subprocess Input: Why Your stdin is Hanging and How to Fix It with .communicate()
How to fix Always use await process.stdin.drain() after a write() to pause until the buffer is clear, and call process.stdin.close() when you're done sending all data. The stdin stream generally expects bytes, not strings.
🌐
Sentry
sentry.io › sentry answers › python › read user input (stdin) in python
Read user input (STDIN) in Python | Sentry
November 15, 2023 - If we run our script without piped input, it will wait for us to enter something into stdin. We can then type or paste in multiple lines, finishing with Ctrl-D: $ python stdin_reader.py Many years later, as he faced the firing squad, Colonel ...
🌐
GitHub
github.com › orgs › micropython › discussions › 11448
Non blocking read of input from the terminal · micropython · Discussion #11448
May 9, 2023 - """ class TermRead: """ We create a select.poll() object called spoll, and register the standard input (sys.stdin) with the POLLIN flag, indicating that we want to wait for the standard input to be ready for reading.
Top answer
1 of 1
7

The POSIX I/O functions that ultimately underlie Python's file objects have two different modes, blocking and non-blocking, controlled by a flag named O_NONBLOCK. In particular, the read function says:

When attempting to read a file … that … has no data currently available … If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].

In Python, this flag is available in the os module.


sys.stdin is already open, so you can't just pass O_NONBLOCK to the os.open function, so… what do you do? Well, you actually might want to open /dev/tty instead; it kind of depends on what you're actually doing. In that case, the answer is obvious. But let's assume that you don't. So, you want to change the flags of the already-open file. That's exactly what fcntl is for. You use the F_GETFL operation to read the current flags, or in the bit for O_NONBLOCK, and F_SETFL the result. You can remember the current flags for later if you want to restore things, of course.

In Python, the fcntl function, and the operation constants, are available in the fcntl module.


One last problem: sys.stdin isn't a raw file object, it's a TextIOWrapper that does Unicode decoding on top of a BufferedReader, which itself adds buffering on top of a FileIO. So, sys.stdin.read() isn't directly calling the POSIX read function. In order to do that, you need to use sys.stdin.buffer.raw. And you may also need to do lots of careful flushing if you want to go back and forth between raw and normal input. (Note that this means you're giving up Unicode and instead getting a single-byte bytes object, which could be, say, half of a UTF-8 character or a quarter of a terminal escape character. Hopefully you're expecting that.)


Now, what does FileIO.read return when nothing is available? Well, it's an implementation of RawIOBase, and RawIOBase.read says:

If 0 bytes are returned, and size was not 0, this indicates end of file. If the object is in non-blocking mode and no bytes are available, None is returned.

In other words, you're going to get None if nothing is available, b'' for EOF, or a single-byte bytes for anything else.


So, putting it all together:

old_settings = termios.tcgetattr(fd)
old_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
try:
    tty.setraw(fd)
    fcntl.fcntl(fd, fcntl.F_SETFL, old_flags | os.O_NONBLOCK)
    return sys.stdin.buffer.raw.read(1)
finally:
    fcntl.fcntl(fd, fcntl.F_SETFL, old_flags)
    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)

One last thing: Is there a way to tell if input is ready without reading it? Yes, but not portably. Depending on your platform, select, poll, epoll, and/or kqueue may be available and may work on regular files. read(0) may be guaranteed to return b'' instead of None. And so on. You can read your local man pages. But a simpler solution is the same thing C's stdio does: add a 1-byte-max buffer, and use it to implement your own read and peek or read and unread wrappers.

🌐
Linux Hint
linuxhint.com › python_pause_user_input
Python Pause For User Input – Linux Hint
If you want to wait for the user to press any key before terminating the script then you can call input() method with a message at the end of the script. The following script shows how you can pause the termination of the script and wait for the user’s input.
🌐
Computer Science Atlas
csatlas.com › python-subprocess-run-stdin
Python 3: Standard Input with subprocess.run() — Computer Science Atlas
September 3, 2021 - The following example loads the ... to the user's current directory. Since standard input is provided by input=data, the Python program will not wait for the user to input anything....
🌐
UltaHost
ultahost.com › knowledge-base › read-from-stdin-python
How to Read From stdin in Python | Ultahost Knowledge Base
March 14, 2025 - In this code, the input() function displays the prompt (`”Enter your name: “`). It waits for the user to enter text and captures the value as a string. The print() function outputs the personalized greeting using the captured input. The sys.stdin module allows you to read data as if stdin were a file.