【问题标题】:Python argparse mutually exclusive with stdin being one of the optionsPython argparse 与 stdin 互斥是选项之一
【发布时间】:2018-08-18 10:12:21
【问题描述】:

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

  • 包含 JSON (script.py -i input.json) 的输入文件;
  • 包含 JSON (script.py '{"a":1}') 的字符串;
  • 来自标准输入的 JSON(echo '{"a":1}' | script.pycat 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

【问题讨论】:

    标签: python json python-3.x stdin argparse


    【解决方案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.pycat 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。但我认为寻找一个简单的- 字符串是一个更好的主意。

    【讨论】:

      猜你喜欢
      • 2017-01-17
      • 2021-12-20
      • 2011-06-09
      • 2014-07-29
      • 2020-07-29
      • 2011-06-13
      • 2012-03-11
      • 1970-01-01
      相关资源
      最近更新 更多