0

我想知道如何使用 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())

这处理标准输入和文件输入:

$ 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 界面的任何想法?

4

2 回答 2

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!
于 2013-10-05T12:51:59.857 回答
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和编号,但应该作为许多应用程序的良好框架。

于 2013-10-09T19:58:35.360 回答