灵活的UNIX命令行界面与Python

时间:2013-10-05 12:49:27

标签: python command-line-interface argparse

我想知道如何使用Python创建灵活的CLI界面。到目前为止,我已经提出以下建议:

$ cat cat.py
#!/usr/bin/env python

from sys import stdin
from fileinput import input
from argparse import ArgumentParser, FileType

def main(args):

   for line in input():
      print line.strip()

if __name__ == "__main__":
   parser = ArgumentParser()
   parser.add_argument('FILE', nargs='?', type=FileType('r'), default=stdin)
   main(parser.parse_args())

它处理stdin和文件输入:

$ echo 'stdin test' | ./cat.py
stdin test

$ ./cat.py file
file test

问题是它没有按照我想要的方式处理多个输入或没有输入:

$ ./cat.py file file
usage: cat.py [-h] [FILE]
cat.py: error: unrecognized arguments: file

$ ./cat.py 

对于多个输入,它应该多次cat文件,对于没有输入输入,理想情况下应该具有与-h相同的行为:

$ ./cat.py -h
usage: cat.py [-h] [FILE]

positional arguments:
  FILE

optional arguments:
  -h, --help  show this help message and exit

有关使用Python创建灵活CLI界面的任何想法吗?

2 个答案:

答案 0 :(得分:4)

使用nargs='*'允许0个或多个参数:

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument('FILE', nargs='*', type=FileType('r'), default=stdin)
    main(parser.parse_args())

现在的帮助输出是:

$ bin/python cat.py -h
usage: cat.py [-h] [FILE [FILE ...]]

positional arguments:
  FILE

optional arguments:
  -h, --help  show this help message and exit

当没有给出参数时,使用stdout

如果您想要至少需要一个FILE参数,请改用nargs='+',但默认会被忽略,因此您可以删除它:

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument('FILE', nargs='+', type=FileType('r'))
    main(parser.parse_args())

现在不指定命令行参数给出:

$ bin/python cat.py
usage: cat.py [-h] FILE [FILE ...]
cat.py: error: too few arguments

您仍然可以通过传递stdin作为参数来指定-

$ echo 'hello world!' | bin/python cat.py -
hello world!

答案 1 :(得分:2)

一个非常好的CLI界面,处理文件输入,标准输入,无输入,文件输出和就地编辑:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def main(args, help):
    '''
    Simple line numbering program to demonstrate CLI interface
    '''

    if not (select.select([sys.stdin,],[],[],0.0)[0] or args.files):
        help()
        return

    if args.output and args.output != '-':
        sys.stdout = open(args.output, 'w')

    try:
        for i, line in enumerate(fileinput.input(args.files, inplace=args.inplace)):
            print i + 1, line.strip()
    except IOError:
        sys.stderr.write("%s: No such file %s\n" % 
                        (os.path.basename(__file__), fileinput.filename()))

if __name__ == "__main__":
    import os, sys, select, argparse, fileinput
    parser = argparse.ArgumentParser()
    parser.add_argument('files', nargs='*', help='input files')
    group = parser.add_mutually_exclusive_group()
    group.add_argument('-i', '--inplace', action='store_true', 
                       help='modify files inplace')
    group.add_argument('-o', '--output', 
                       help='output file. The default is stdout')
    main(parser.parse_args(), parser.print_help)

代码只是模拟nl并对行进行编号,但应该作为许多应用程序的良好框架。