5

I have a script that is designed to accept input piped in from stdin and then prompt the user for more input. Here is a contrived example illustrating what I mean:

import sys

# Get input from stdin
input_nums = [int(n.strip()) for n in sys.stdin]

# Prompt user
mult = int(raw_input("Enter a number by which to multiply your input: "))

for num in input_nums:
    print num*mult

When I pipe data in from stdin, python interprets stdin as closed before it gets to raw_input and it gives an EOFError: EOF when reading a line:

[user]$ cat nums.txt
2
3
4
5
[user]$ cat nums.txt | python sample.py
Enter a number by which to multiply your input: Traceback (most recent call last):
  File "sample.py", line 6, in <module>
    mult = int(raw_input("Enter a number by which to multiply your input: "))
EOFError: EOF when reading a line

(Please don't worry about the useless use of cat... its just a minimal example)

What I want to know is if there is a way to somehow separate reading sys.stdin and calling raw_input so that I can both pipe in data and then prompt a user for input.

Updated to make it more clear what I really want by eliminating red herrings, and added traceback of EOFError

Result @TimPeter's solution worked for me, but I had to change "CON:" to "/dev/tty" since I'm on UNIX, not Windows.

SethMMorton
  • 45,752
  • 12
  • 65
  • 86

1 Answers1

6

I suspect you're out of luck, at least for any kind of cross-platform solution. Python uses sys.stdin for raw_input(), and if you invoke Python so that sys.stdin is on the receiving end of a pipe, Python can't do anything to magically change sys.stdin to the terminal when the piped input ends.

Here's a variant of the question with a Unix-specific workaround as the accepted answer. That cleverly worms around some (not all) of the problem by changing the way the program is invoked.

Sorry.

One way

This seems to work fine for Windows:

import sys
print len(sys.stdin.read()) # anything to consume piped input
sys.stdin = open("CON:", "r")
x = raw_input("sdfklj ")

That is, after reading the piped-in input, sys.stdin is rebound to the special file CON: (which is what Windows calls a DOS box) opened in read mode.

See your Unix docs for what to try there - perhaps /dev/tty1? There are mounds of terminal control options you may need to fiddle with too, depending on platform specifics. That's why I said (at the start) that I think you're out of luck for any cross-platform solution. Python has no special support for terminal devices; i.e., you're on your own for that.

Community
  • 1
  • 1
Tim Peters
  • 67,464
  • 13
  • 126
  • 132
  • Thanks, but this is a program that I will be used by my co-workers, and I don't want to force them to call the script in an odd way. Good suggestion, though. – SethMMorton Oct 04 '13 at 03:41
  • Then do your coworkers a favor and give them just one way to run the program - then it will work, and they won't be confused either - LOL ;-) Seriously, can you think of any other program, of any kind, that works the way you intend here? Excessive novelty is confusing on its own. – Tim Peters Oct 04 '13 at 03:45
  • Even if I were to choose to only accept piped in data, I would need to still prompt the user for data. Let me edit the question to make that more clear. In reality the program is more complex and prompting the user is a must, and the input data is taken from the output of another co-worker's program. – SethMMorton Oct 04 '13 at 03:50
  • And yes, grep works this way (without the prompting, of course) – SethMMorton Oct 04 '13 at 03:53
  • I admire determination ;-) I added an edit showing how to do it on Windows. It "should be" easier on Unix-y systems, but somehow I doubt it ;-) – Tim Peters Oct 04 '13 at 04:18
  • YEAH! It works on UNIX when I replace "CON:" with "/dev/tty". I don't need a cross platform solution, but if one did, maybe a `if sys.plaform == 'win32'... else` could work in this situation. – SethMMorton Oct 04 '13 at 04:38
  • Woohoo! Delighted to hear it, @SethMMorton - now just think of a way we can get rich off this - LOL ;-) – Tim Peters Oct 04 '13 at 04:44
  • I realize that this is bad form, but could you take a look at [my question about Python's C API](http://stackoverflow.com/q/20875520/1399279)? I was hoping that one of the core developers could provide some insight. – SethMMorton Feb 10 '14 at 18:39