Python argparse 与 stdin 互斥是选项之一
Posted
技术标签:
【中文标题】Python argparse 与 stdin 互斥是选项之一【英文标题】:Python argparse mutually exclusive with stdin being one of the options 【发布时间】:2018-08-18 10:12:21 【问题描述】:我希望我的脚本接收这些互斥的输入选项:
包含 JSON (script.py -i input.json
) 的输入文件;
包含 JSON (script.py '"a":1'
) 的字符串;
来自标准输入的 JSON(echo '"a":1' | script.py
或 cat input.json | script.py
)。
以及这些相互排斥的输出选项:
包含 JSON 的输出文件; 标准输出中的 JSON。所以我尝试了这段代码
import json,sys,argparse
parser = argparse.ArgumentParser(description='Template for python script managing JSON as input/output format')
group = parser.add_mutually_exclusive_group()
group.add_argument('--input-file', '-i', type=str, help='Input file name containing a valid JSON.', default=sys.stdin)
group.add_argument('json', nargs='?', type=str, help='Input string containing a valid JSON.' , default=sys.stdin)
parser.add_argument('--output-file', '-o',type=str, help='Output file name.')
args = parser.parse_args()
if not sys.stdin.isatty():
data = sys.stdin.read()
else:
# args = parser.parse_args()
if args.input_file :
data=open(args.input_file).read()
elif args.json :
data=args.json
datain=json.loads(data)
dataout=json.dumps(datain, indent=2)
if args.output_file :
output_file=open(args.output_file, 'w')
output_file.write(dataout+'\n')
output_file.close()
else:
print (dataout)
但它不适用于标准输入,因为它至少需要两个 group
选项之一。
如何在输入选项列表中添加标准输入?
如果我这样称呼它,添加 default=sys.stdin
参数会起作用
echo '' | ./script.py -
但不是那样:
echo '' | ./script.py
【问题讨论】:
【参考方案1】:我会利用argparse.FileType
的默认值sys.stdin
。
import json,sys,argparse
parser = argparse.ArgumentParser(description='Template for python script managing JSON as input/output format')
group = parser.add_mutually_exclusive_group()
group.add_argument(
'--input-file', '-i',
type=argparse.FileType('r'),
default=sys.stdin,
help='Input file name containing a valid JSON.')
group.add_argument(
'json',
nargs='?',
type=str,
help='Input string containing a valid JSON.')
parser.add_argument(
'--output-file', '-o',
type=argparse.FileType('w'),
help='Output file name.',
default=sys.stdout)
args = parser.parse_args()
data = args.json or args.input_file.read()
datain=json.loads(data)
dataout=json.dumps(datain, indent=2)
args.output_file.write(dataout)
【讨论】:
太棒了!但是使用此代码,空标准输入和无参数 (.\script.py
) 会导致无限期等待,而它应该(在我看来)表明至少需要一种方法(标准输入、字符串或文件)
那么一种类型如何输入到你的程序中呢? “从标准输入读取”是指输入未重定向时从控制台读取。
抱歉使用了错误的术语:) 我的意思是输入来自管道,例如echo '' | script.py
或cat input.json | script.py
。
对。这是使用标准输入的一种方式。但同样有效的方法是在程序运行时键入。如果你故意排除通过在控制台输入文本到程序中的能力,那会让你的用户感到困惑。
对,它正在等待下一行文本。毕竟,您的数据可能超过一行。完成数据输入后,按操作系统使用的文件结束键序列指示文件结束。如果您使用的是 UNIX 或 Linux,那可能是 Control-D。如果你在 Windows 上,它可能是 Control-Z。【参考方案2】:
与:
group.add_argument('--input-file', '-i')
你可以测试
if args.input_file is None:
<-i wasn't supplied>
else:
if args.input_file == '-':
f = sys.stdin
else:
f = open(args.input_file)
data = f.read() # etc
或者可能更好:
if args.input_file == '-':
data = sys.stdin.read()
else
with open(args.input_file) as f:
f.read()
stdin
的一个棘手问题是您不想在使用后关闭它,就像使用常规文件名一样。而且你不能在with
中使用它。
与stdout
类似。
一些代码在打开文件时设置一个标志,而不是接收一个已经打开的标志,因此它可以记住在最后关闭文件。
group.add_argument('--input-file','-i',nargs='?', default=None, const=sys.stdin)
当给定-i
而不带参数时,会将arg.input_file
设置为stdin
。但我认为寻找一个简单的-
字符串是一个更好的主意。
【讨论】:
以上是关于Python argparse 与 stdin 互斥是选项之一的主要内容,如果未能解决你的问题,请参考以下文章
与两个连接的 python3 脚本一起使用时的 argparse 冲突
如何根据 Python 中的位置参数与 argparse 的组合设置不同的选项?