Paul Draper Paul Draper - 3 months ago 10
Linux Question

sys.stdin does not close on ctrl-d

I have the following code in program.py:

from sys import stdin
for line in stdin:
print line


I run, enter lines, and then press Ctrl+D, but the program does not exit.

This does work:

$ printf "echo" | python program.py


Why does the program not exit when I press Ctrl+d?
I am using the Fedora 18 terminal.

Answer

Ctrl+D has a strange effect. It doesn't close the input stream, but only causes a C-level fread() to return an empty result. For regular files such a result means that the file is now at its end, but it's acceptable to read more, e.g. to check if someone else wrote more data to the file in the meantime.

In addition, there are issues of buffering --- three levels of them!

  • Python's iteration over a file does block buffering. Avoid it to read from interactive streams.

  • the C-level stdin file has, by default, a line buffer.

  • the terminal itself(!), in its default mode ("cooked mode"), reads one line of data before sending it to the process, which explains why typing Ctrl+D doesn't have any effect when typed in the middle of a line.

This example avoids the first issue, which is all you need if all you want is detecting Ctrl+D typed as its own line:

import sys

while True:
   line = sys.stdin.readline()
   print repr(line)

You get every line with a final '\n', apart from when the "line" comes from a Ctrl+D, in which case you get just '' (but reading continues, unless of course we add if line == '': break).