Python argparse 与 stdin 互斥是选项之一

Python argparse mutually exclusive with stdin being one of the options

我希望我的脚本接收这些互斥的输入选项:

和这些互斥的输出options:

所以我尝试使用此代码

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

我会利用 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)

与:

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。但我认为寻找一个普通的 - 字符串是一个更好的主意。