5

While playing with sys.stdin.read() (Terminal, Mac OS Sierra), found weird behavior where it becomes unusable. What's happening?

# Python 2.7.13

import sys
sys.stdin.read()
# waits for input
# user presses ctrl-d (without any input)
# returns ''
sys.stdin.read()
# doesn't wait for input
# immediately returns ''

sys.stdin.read()
# ''
sys.stdin.read()
# ''

Note: ctrl+d = EOF on Mac, ctrl+z on Windows

Update: I've noticed the same behavior for any string of length 5 with one new line...shorter/longer strings or more/less new lines behave properly...

# Python 2.7.13

import sys
sys.stdin.read()
12345
# press ctrl-d twice (only way to make single line string work?)
'12345'
# worked properly

sys.stdin.read()
1234
# user presses return and then ctrl-d
'1234\n'
# worked properly

sys.stdin.read()
12345
# return, return, ctrl-d

'12345\n\n'
# worked properly

sys.stdin.read()
12345
# return, ctrl-d
'12345\n'
# didn't work...see next call

sys.stdin.read()
# doesn't wait for input
# immediately returns ''
''

I would like to understand what causes this behavior as I'm using it in a program. I'll be sure to check for it in the code but still would like to understand how to avoid these two instances where it doesn't work.

JBallin
  • 8,481
  • 4
  • 46
  • 51
  • 2
    I'm not sure, which is why I'm not posting an answer, but I think it's right there in the question: EOF is end of *file*, not end of line. EOF signifies that there will be no more input at all. While that's not a hard technical requirement (it is, after all, just a character), Terminal (or, for that matter, Python) might be treating it specially (my guess is Terminal). – Linuxios May 16 '17 at 22:37
  • 1
    Interestingly, I can only get this on Python2.7. In Python3.6, each call to `read()` waits for input and returns `^D` each time it is pressed. (On OS X El Capitan, and using either iTerm2 or Terminal.app. – bnaecker May 16 '17 at 23:13
  • Ok, looking around a bit more, this may be related to this SO post (https://stackoverflow.com/questions/1892215/how-to-send-eof-to-python-sys-stdin-from-commandline-ctrl-d-doesnt-work) and this Python bug (https://bugs.python.org/issue3907). The underlying implementation of the reading methods are not buffered the same way between Python2 and 3. If I use Python2, and change `sys.stdin.read()` to `sys.stdin.readline()`, then the behavior is the same in Python2 and 3. – bnaecker May 16 '17 at 23:15
  • 1
    Pretty sure that `''` is the return value that means "EOF" for `stdin`. That's why you set that as the EOF signal for things like subprocess pipes. The Python 2 implementation just refused to return anything past the first EOF, which is actually pretty sensible, even if not always correct. – Mad Physicist May 17 '17 at 21:27

0 Answers0