上下文
我想要一个简单的脚本,在Unix/Linux上选择多个管道输入中的一个,而不会出现EOF when reading a line
错误。
它试图:
预期用途:
$ 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}'
只是为了显示唯一的标准输出应该是选择。
现行办法:
#!/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()
再次阻塞并像通常那样等待用户。
简单地说:在从input()
stdin
**?**读取文件之后,如何使用
如果这是不可能的,as this answer implies,有什么优雅的解决方案可以得到类似于我在这个问题开头描述的行为呢?我对非python解决方案(例如bash\zsh、锈病、awk、perl)持开放态度。
发布于 2021-02-10 11:18:24
我可以为Linux/Unix回答您的问题。对不起,我不使用Windows。
我在示例代码中添加了两行代码,如下所示。
特殊设备/dev/tty
连接到您的终端。除非重定向,否则这是您的标准输入/输出。基本上,您希望恢复stdin连接到您的终端的状态。在较低的级别上,它使用文件描述符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)
发布于 2021-02-10 11:24:04
VPfB's answer是我所需要的,这是最后定稿的脚本,以防有人想要使用它。
用法
$ 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()
https://stackoverflow.com/questions/66142884
复制相似问题