Подтвердить что ты не робот

Ввод трубы в программу Python и последующий ввод данных от пользователя

Скажем, я хочу подключить вход к программе 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, а затем запрашивать пользователя для ввода.

4b9b3361

Ответ 1

Нет общего решения этой проблемы. Лучший ресурс, кажется, этот поток списка рассылки.

В принципе, подключение к программе подключает программу stdin к этому каналу, а не к терминалу.

В потоке списка рассылки есть несколько относительно простых решений для * nix:

Открыть /dev/tty для замены sys.stdin:

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

Перенаправить stdin в другой дескриптор файла при запуске script и прочитать из этого:

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

а также предложение использовать проклятия. Обратите внимание, что поток списка рассылки древний, поэтому вам может потребоваться изменить выбранное решение.

Ответ 2

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 все равно будет доступен для чтения ввода с клавиатуры.

Ответ 3

Сделал это, чтобы подражать raw_input(), так как у меня была такая же проблема, как и вы. Целый stdin и clear уродство - просто заставить его выглядеть красиво. Чтобы вы могли видеть, что вы набираете.

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

Ответ 4

Я обновил @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)