簡體   English   中英

從`stdin`讀取文件后如何使用`input()`?

[英]How to use `input()` after reading a file from `stdin`?

語境

我想要一個簡單的腳本,在 Unix/Linux 上EOF when reading a line

它試圖:

  1. 接受多行管道文本
  2. 等待用戶 select 一個選項
  3. 將該選項打印到標准輸出

所需用途:

$ printf "A\nB" | ./select.py | awk '{print "OUTPUT WAS: " $0}'
Select 0-1:
  0) A
  1) B
> 1
OUTPUT WAS: B

最后的awk '{print "[OUTPUT WAS] " $0}'只是為了表明唯一的標准輸出 output 應該是選擇。

目前的做法:

#!/bin/python3
import sys
from collections import OrderedDict

def print_options(options):
    """print the user's options"""
    print(f"Select 0-{len(options)-1}:", file=sys.stderr)
    for n, option in options.items():
        print(f"  {n}) {option}", file=sys.stderr)

def main():
    # options are stored in an ordered dictionary to make order consistent
    options = OrderedDict()
    # read in the possible options one line at a time
    for n, line in enumerate(sys.stdin):
        options[n] = line.rstrip('\n')
        
    valid_selection = False
    # loop until we get a valid selection
    while not valid_selection:
        print_options(options)
        try:
            print('> ', end='', file=sys.stderr)
            selection = int(input()) # <- doesn't block like it should
            # use the selection to extract the output that will be printed
            output = options[selection]
            valid_selection = True
        except Exception as e:
            print(f"Invalid selection. {e}", file=sys.stderr)
                
    print(output)

if __name__ == '__main__':
    main()

錯誤:

腳本陷入無限循環打印:

...
> Invalid selection. EOF when reading a line
Select 0-1:
  0) A
  1) B
> Invalid selection. EOF when reading a line
Select 0-1:
  0) A
  1) B
> Invalid selection. EOF when reading a line
...

重現錯誤的最小腳本:

#!/bin/python3
import sys

options = []
# read in the possible options one line at a time
for line in sys.stdin:
    options.append(line.rstrip('\n'))
    
user_input = input('> ')
            
print(user_input)

這拋出:

EOFError: EOF when reading a line

當我想查看和輸入時:

$ printf "text" | ./testscript.py
> sometext
sometext

所需的解決方案:

我認為這是由於 stdin 已達到 EOF 的事實。 但我的問題是如何重置/消除 EOF 的影響,以便input()再次阻塞並像往常一樣等待用戶。

簡而言之:stdin讀取文件后如何使用input()

如果這是不可能的,正如這個答案所暗示的那樣,有什么優雅的解決方案可以得到與我在這個問題開頭所描述的類似的行為? 我對非 python 解決方案持開放態度(例如 bash|zsh、rust、awk、perl)。

我可以回答你關於 Linux/Unix 操作系統的問題。 對不起,我不使用 Windows。

我在您的示例代碼中添加了兩行,見下文。

特殊設備/dev/tty連接到您的終端。 除非重定向,否則它是您的標准輸入/輸出。 基本上你想恢復你的標准輸入連接到你的終端的 state。 在低級別上,它與文件描述符 0 一起使用。 close將其關閉,而open則采用第一個空閑的,在這種情況下為 0。

import sys 

options = []
# read in the possible options one line at a time
for line in sys.stdin:
    options.append(line.rstrip('\n'))

# restore input from the terminal   
sys.stdin.close()
sys.stdin=open('/dev/tty')

user_input = input('> ')
                 
print(user_input)

VPfB 的答案是我所需要的,這是最終腳本,以防有人想使用它。

用法

$ printf "A\nB\nC" | ./select.py | awk '{print "Selected: " $0}'
Select 0-1:
  0) A
  1) B
  2) C
> 2 <- your input
Selected: C

完整的解決方案

#!/bin/python3
"""
A simple script to allow selecting 1 of multiple piped inputs. 

Usage: 
printf "A\nB" | ./choose.py

If your input is space separated, make sure to convert with: 
printf "A B" | sed 's+ +\n+g' | ./choose.py

Source: https://stackoverflow.com/a/66143667/7872793
"""
import sys
from collections import OrderedDict

def print_options(options):
    """print the user's options"""
    print(f"Select 0-{len(options)-1}:", file=sys.stderr)
    for n, option in options.items():
        print(f"  {n}) {option}", file=sys.stderr)

def select_loop(options):
    valid_selection = False
    # loop until we get a valid selection
    while not valid_selection:
        print_options(options)
        try:
            print('> ', end='', file=sys.stderr)
            selection = int(input())
            # use the selection to extract the output that will be printed
            output = options[selection]
            valid_selection = True
        except Exception as e:
            print(f"Invalid selection. {e}", file=sys.stderr)
            
    return output

def main():
    # options are stored in an ordered dictionary to fix iteration output
    options = OrderedDict()
    # read in the possible options one line at a time
    for n, line in enumerate(sys.stdin):
        options[n] = line.rstrip('\n')
        
    # restore input from the terminal
    sys.stdin.close()
    sys.stdin=open('/dev/tty')
        
    # if only one option is given, use it immediately
    output = options[0] if len(options) == 1 else select_loop(options)
    print(output)

if __name__ == '__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM