我正在尝试指定一个带stdin的可选参数。这将主要用于我的程序中的管道数据,因此someprog that outputs | python my_prog
。
我遵循了argparse文档,我在Stackoverflow上阅读了很多问题/答案,但似乎没有一个对我有用。
这是我最初拥有的:
parser = argparse.ArgumentParser(description='Upgrade Instance.')
parser.add_argument('--app', '-a', dest='app', action='store', required=True)
parser.add_argument('--version', '-v', dest='version', action='store', default='', required=False)
parser.add_argument('--config', '-c', dest='config', action='store', default = '', required=False)
args = parser.parse_args()
现在我要做的是允许用户使用管道传递version
,而不是传入。
我在顶部添加了parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
,但这使它成为一个位置参数。怎么可能?我认为nargs=?
使其成为可选项。
我需要它作为一个可选参数。所以我把它改成了:
parser.add_argument('--infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
这使它成为一个可选参数,但如果没有传递管道,程序会挂起等待stdin,因为它是默认值。删除default=sys.stdin
并在我的程序中输入一些东西:
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
运行时。当我打印args
时,我得到:Namespace(app='app', config='', g=False, hosts='03.app', infile=None, version='')
。
看起来我正在做的事情很简单,很常见,许多人都在询问它。但它似乎并没有与我合作。
关于如何让它发挥作用的任何建议?
答案 0 :(得分:4)
这样做......没有指定参数。如果你将管道输入传递给程序,那么你就不会,它仍然存在。 raw_input()
也可以使用。
import sys
if not sys.stdin.isatty():
stdin = sys.stdin.readlines()
print stdin
sys.stdin = open('/dev/tty')
else:
print "No stdin"
test_raw = raw_input()
print test_raw
演示 -
rypeck$ echo "stdin input" | python test_argparse.py -a test
['stdin input\n']
raw_input working!
raw_input working!
rypeck$ python test_argparse.py -a test
No stdin
raw_input working!
raw_input working!
答案 1 :(得分:3)
我自己正在探讨这个问题,并在这里找到了一些改进 - 希望它能帮助未来的旅行者。如果您希望在提供标志时仅从标准输入读取,那么这不是100%清楚,但似乎这可能是您的目标;我的回答是基于这个假设。我在3.4工作,如果成为一个问题......
我可以声明一个可选的参数,如:
parser.add_argument("-v", "--version", nargs='?', const=sys.stdin, action=StreamType)
我没有指定默认值,因为仅当选项完全不存在时才使用它,而const仅在标志存在但没有参数时使用。 StreamType
是我编写的一个小argparse.Action
子类,只是尝试从stdin流中读取一行,如果不起作用,只保存原始值:
class StreamType(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
try:
setattr(namespace, self.dest, values.readline().strip())
except AttributeError:
setattr(namespace, self.dest, values)
这应该产生类似的东西:
$ blah --version v1.1.1
Namespace(version='v1.1.1')
$ echo "v1.0.3" | blah --version
Namespace(version='v1.0.3')
答案 2 :(得分:2)
你对args.infile
做了什么?因为你得到一个命名空间,argparse
不是挂起或给出错误的部分。
p = argparse.ArgumentParser()
p.add_argument('--infile', type=argparse.FileType('r'),default='-')
# p.add_argument('infile', nargs='?', type=argparse.FileType('r'),default='-') # positional version
args = p.parse_args()
print(args)
print args.infile.read()
-----------
$ cat myprog.py | python myprog.py --infile -
$ cat myprog.py | python myprog.py
$ python myprog.py myprog.py # with the positional version
$ python myprog.py - < myprog.py # with the positional version
很好地回应了代码。第二个电话与“可选位置”一起使用&#39;同样。
术语optional/positional
和optional/required
存在令人遗憾的重叠。
如果位置参数(是,另一种使用&#39;位置&#39;)具有-
或--
这样的前缀字符,则称为optional
。默认情况下,其required
参数为False
,但您可以将其设置为True
。但如果参数为'infile'
(无前缀),则为positional
,即使?
为optional
(不是必需的)。
顺便说一句,默认action
为'store'
,因此您无需指定。{此外,您不需要指定required
,除非它是True
。
使用FileType
,指定stdin
的便捷方式是-
。
除非您真的需要'?'
--infile
与None
一起使用