Pipe input to Python program and later get input from user

后端 未结 5 922
借酒劲吻你
借酒劲吻你 2020-12-13 10:53

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          


        
相关标签:
5条回答
  • 2020-12-13 11:14

    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.

    0 讨论(0)
  • 2020-12-13 11:17

    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.

    0 讨论(0)
  • 2020-12-13 11:18

    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
    
    0 讨论(0)
  • 2020-12-13 11:22

    I updated @Bob's answer to support delete, ctrl + [left, right, home, end] keypresses and simplified the stdout clearing and rewriting.

    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)
    
    0 讨论(0)
  • 2020-12-13 11:26

    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()
    
    0 讨论(0)
提交回复
热议问题