Pipe input to Python program and later get input from user

Let's say I want to pipe input to a Python program, and then later get input from the user, on the command line.

echo http://example.com/image.jpg | python solve_captcha.py

and the contents of solve_captcha.py are:

import sys 
image_url = sys.stdin.readline()

# Download and open the captcha...

captcha = raw_input("Solve this captcha:")
# do some processing...

The above will trigger a EOFError: EOF when reading a line error.

I also tried adding a sys.stdin.close() line, which prompted a ValueError: I/O operation on closed file.

Can you pipe information to stdin and then later get input from the user?

Note: This is a stripped down, simplified example - please don't respond by saying "why do you want to do that in the first case," it's really frustrating. I just want to know whether you can pipe information to stdin and then later prompt the user for input.


Solution 1:

There isn't a general solution to this problem. The best resource seems to be this mailing list thread.

Basically, piping into a program connects the program's stdin to that pipe, rather than to the terminal.

The mailing list thread has a couple of relatively simple solutions for *nix:

Open /dev/tty to replace sys.stdin:

sys.stdin = open('/dev/tty')
a = raw_input('Prompt: ')

Redirect stdin to another file handle when you run your script, and read from that:

sys.stdin = os.fdopen(3)
a = raw_input('Prompt: ')
$ (echo -n test | ./x.py) 3<&0

as well as the suggestion to use curses. Note that the mailing list thread is ancient so you may need to modify the solution you pick.

Solution 2:

bash has process substitution, which creates a FIFO, which you can treat like a file, so instead of

echo http://example.com/image.jpg | python solve_captcha.py

you can use

python solve_capcha.py <(echo http://example.com/image.jpg)

You would open first argument to solve_capcha.py as a file, and I think that sys.stdin would still be available to read input from the keyboard.

Solution 3:

You can close stdin and then reopen it to read user input.

import sys, os

data = sys.stdin.readline()
print 'Input:', data
sys.stdin.close()
sys.stdin = os.fdopen(1)
captcha = raw_input("Solve this captcha:")
print 'Captcha', captcha

Solution 4:

Made this up to emulate raw_input(), since I had the same problem as you. The whole stdin and clear ugliness is simply to make it look pretty. So that you can see what you are typing.

def getInputFromKeyPress(promptStr=""):

    if(len(promptStr)>0):
        print promptStr
    """
    Gets input from keypress until enter is pressed
    """

    def clear(currStr):
        beeString, clr="",""

        for i in range(0,len(currStr)):
            clr=clr+" "
            beeString=beeString+"\b"

        stdout.write(beeString)
        stdout.write(clr)
        stdout.write(beeString)


    from msvcrt import kbhit, getch
    from sys import stdout
    resultString, userInput="", ""

    while(userInput!=13):
        if (kbhit()):
            charG=getch()
            userInput= ord(charG)

            if(userInput==8):#backspace
                resultString=resultString[:-1]
                clear(resultString)


            elif(userInput!=13):
                resultString="".join([resultString,charG])

            clear(resultString)
            stdout.write(resultString)

            if(userInput==13):
                clear(resultString)

    #print "\nResult:",resultString

    return resultString.strip()