管道输入到Python程序,然后从用户获取输入

时间:2011-08-21 21:34:33

标签: python bash stdin

假设我想将输入传递给Python程序,然后在命令行上从用户那里获得输入。

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

并且solve_captcha.py的内容是:

import sys 
image_url = sys.stdin.readline()

# Download and open the captcha...

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

上述操作会触发EOFError: EOF when reading a line错误。

我还尝试添加sys.stdin.close()行,其中提示ValueError: I/O operation on closed file

您可以将信息传递给stdin,然后再从用户那里获得输入吗?

注意:这是一个简化的简化示例 - 请不要回答说“你为什么要在第一种情况下这样做”,这真的令人沮丧。我只想知道您是否可以将信息传递给stdin,然后提示用户输入。

5 个答案:

答案 0 :(得分:13)

这个问题没有一般解决方案。最好的资源似乎是this mailing list thread

基本上,流入程序会将程序的stdin连接到该管道,而不是连接到终端。

邮件列表主题有一些相对simple solutions的* nix:

打开/ dev / tty替换sys.stdin:

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

运行脚本时将stdin重定向到另一个文件句柄,并从中读取:

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

以及suggestion to use curses。请注意,邮件列表主题古老,因此您可能需要修改您选择的解决方案。

答案 1 :(得分:5)

bash有进程替换,它创建了一个FIFO,您可以将其视为文件,而不是

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

你可以使用

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

您可以将solve_capcha.py的第一个参数作为文件打开,我认为sys.stdin仍可用于从键盘读取输入。

答案 2 :(得分:2)

这样做可以模仿raw_input(),因为我遇到了和你一样的问题。整个stdinclear丑陋只是为了让它看起来很漂亮。这样你就可以看到你在输入什么。

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()

答案 3 :(得分:0)

我更新了@ Bob的答案,支持删除,ctrl + [left,right,home,end]按键,简化了stdout清除和重写。

def keypress_input(prompt_str=""):
    """
    Gets input from keypress using `msvcrt` until enter is pressed.
    Tries to emulate raw_input() so that it can be used with piping.
    :param prompt_str: optional string to print before getting input
    :type prompt_str: str
    """
    from re import finditer
    from msvcrt import getch
    from sys import stdout

    # print even if empty to create new line so that previous line won't be overwritten if it exists
    print prompt_str

    user_input = ""
    curr_chars = []
    cursor_pos = 0

    backspace = 8
    enter = 13

    escape_code = 224
    delete = 83
    left = 75
    right = 77
    home = 71
    end = 79
    ctrl_left = 115
    ctrl_right = 116
    ctrl_home = 119
    ctrl_end = 117

    while user_input != enter:
        char_g = getch()
        user_input = ord(char_g)
        prev_len = len(curr_chars)  # track length for clearing stdout since length of curr_chars might change

        if user_input == backspace:
            if len(curr_chars) > 0 and cursor_pos <= len(curr_chars):
                cursor_pos -= 1
                curr_chars.pop(cursor_pos)

        elif user_input == escape_code:
            user_input = ord(getch())

            if user_input == delete:
                curr_chars.pop(cursor_pos)

            elif user_input == left:
                cursor_pos -= 1

            elif user_input == right:
                if cursor_pos < len(curr_chars):
                    cursor_pos += 1

            elif user_input == home:
                cursor_pos = 0

            elif user_input == end:
                cursor_pos = len(curr_chars)

            elif user_input == ctrl_home:
                curr_chars = curr_chars[cursor_pos:]
                cursor_pos = 0

            elif user_input == ctrl_end:
                curr_chars = curr_chars[:cursor_pos]
                cursor_pos = len(curr_chars)

            elif user_input == ctrl_left:
                try:
                    chars_left_of_cursor = "".join(curr_chars[:cursor_pos])
                    left_closest_space_char_index = [m.span()[0] for m in finditer(" \w", chars_left_of_cursor)][-1]
                    pos_diff = cursor_pos - left_closest_space_char_index - 1
                    cursor_pos -= pos_diff
                except IndexError:
                    cursor_pos = 0

            elif user_input == ctrl_right:
                try:
                    chars_right_of_cursor = "".join(curr_chars[cursor_pos + 1:])
                    right_closest_space_char_index = [m.span()[0] for m in finditer(" \w", chars_right_of_cursor)][0]
                    cursor_pos += right_closest_space_char_index + 2
                except IndexError:
                    cursor_pos = len(curr_chars) - 1

        elif user_input != enter:
            if cursor_pos > len(curr_chars) - 1:
                curr_chars.append(char_g)
            else:
                curr_chars.insert(cursor_pos, char_g)
            cursor_pos += 1

        # clear entire line, write contents of curr_chars, reposition cursor
        stdout.write("\r" + prev_len * " " + "\r")
        stdout.write("".join(curr_chars))
        pos_diff = len(curr_chars) - cursor_pos
        stdout.write("\b" * pos_diff)

    stdout.write("\r" + len(curr_chars) * " " + "\r")
    stdout.write("".join(curr_chars) + "\n")

    return "".join(curr_chars)

答案 4 :(得分:0)

您可以关闭stdin,然后重新打开以读取用户输入。

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