首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何在读取“`stdin`”中的文件后使用“How ()”?

如何在读取“`stdin`”中的文件后使用“How ()”?
EN

Stack Overflow用户
提问于 2021-02-10 18:28:01
回答 2查看 248关注 0票数 1

上下文

我想要一个简单的脚本,在Unix/Linux上选择多个管道输入中的一个,而不会出现EOF when reading a line错误。

它试图:

  1. 接受多行管道文本
  2. 等待用户选择一个选项
  3. 打印该选项以输出

预期用途:

代码语言:javascript
代码运行次数:0
运行
复制
$ 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}'只是为了显示唯一的标准输出应该是选择。

现行办法:

代码语言:javascript
代码运行次数:0
运行
复制
#!/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()

错误:

脚本陷入无限循环打印:

代码语言:javascript
代码运行次数:0
运行
复制
...
> 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
...

复制错误的最小脚本:

代码语言:javascript
代码运行次数:0
运行
复制
#!/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)

这会抛出:

代码语言:javascript
代码运行次数:0
运行
复制
EOFError: EOF when reading a line

当我想看到和输入:

代码语言:javascript
代码运行次数:0
运行
复制
$ printf "text" | ./testscript.py
> sometext
sometext

所需解决办法:

我想这是由于stdin已经达到EOF的事实。但是我的问题是如何重置/删除EOF的影响,以便input()再次阻塞并像通常那样等待用户。

简单地说:在从input() stdin**?**读取文件之后,如何使用

如果这是不可能的,as this answer implies,有什么优雅的解决方案可以得到类似于我在这个问题开头描述的行为呢?我对非python解决方案(例如bash\zsh、锈病、awk、perl)持开放态度。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-02-10 19:18:24

我可以为Linux/Unix回答您的问题。对不起,我不使用Windows。

我在示例代码中添加了两行代码,如下所示。

特殊设备/dev/tty连接到您的终端。除非重定向,否则这是您的标准输入/输出。基本上,您希望恢复stdin连接到您的终端的状态。在较低的级别上,它使用文件描述符0。close关闭它,open获得第一个免费的,在这种情况下是0。

代码语言:javascript
代码运行次数: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)
票数 2
EN

Stack Overflow用户

发布于 2021-02-10 19:24:04

VPfB's answer是我所需要的,这是最后定稿的脚本,以防有人想要使用它。

用法

代码语言:javascript
代码运行次数:0
运行
复制
$ printf "A\nB\nC" | ./select.py | awk '{print "Selected: " $0}'
Select 0-1:
  0) A
  1) B
  2) C
> 2 <- your input
Selected: C

全解

代码语言:javascript
代码运行次数:0
运行
复制
#!/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()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66142884

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档