本文共 12440 字,大约阅读时间需要 41 分钟。
# Pythonfrom optparse import OptionParserusage = "here is help messages of the command line tool."opt_parser = OptionParser(usage)opt_parser.add_option('-s', '--switch', action='store_false', help='set options as switch')opt_parser.add_option('-n', '--name', type='string', dest='nickname', help='pass in single name')opt_parser.add_option("-f", "--filename", metavar="FILE", help="write output to FILE")test_args = ['-n', 'looking', '-s', '-f', 'outfile.txt']# python test.py -n looking -s -f outfile.txt(options, args) = opt_parser.parse_args(test_args)# (options, args) = opt_parser.parse_args()print(opt_parser.print_help())print(options)
[root@master python3_learning]# python3 test.pyUsage: here is help messages of the command line tool.Options: -h, --help show this help message and exit -s, --switch set options as switch -n NICKNAME, --name=NICKNAME pass in single name -f FILE, --filename=FILE write output to FILENone{'switch': False, 'nickname': 'looking', 'filename': 'outfile.txt'}
1. add_option 选项里的 -arg1 和 --arg2 一般是对应的,而且默认会把解析的结果保存到 args2 里边,比如下面例子中的 -f 选项:
opt_parser.add_option("-f", "--filename", metavar="FILE", help="write output to FILE")
最终会以 filename 来保存对应的解析结果:
{..., 'filename': 'outfile.txt'}
2. 除非你自己指定了具体的 dest='args3',那么它会以 args3 为变量名保存。比如下面例子的 -n 选项:
opt_parser.add_option('-n', '--name', type='string', dest='nickname', help='pass in single name')
最终会以 nickname (而不是 name)来保存对应的解析结果(如果没有 dest='nickname' 选项,则结果会包含 ‘name': 'looking'):
{..., 'nickname': 'looking', ...}
3. action='store_true' (action='store_false' )表示用户不需给出参数值,该类型定义了将布尔值 true (false) 保存到 dest 指定的变量中,比如下面例子的 -s 选项:
opt_parser.add_option('-s', '--switch', action='store_false', help='set options as switch')
解析 -s 的结果是(如果选项里没有 -s, 则结果为 'switch': None):
{'switch': False, ...}
4. add_option 选项里的 default 参数用于设置默认值:
opt_parser.add_option("-u", "--user", default="root", help="set user to login")
如果参数里边没有指定 -u 的值,则解析结果会使用默认的值:
{..., 'user': 'root'}
据说 argparse 要比 optparse 更强大一些哟。下面例子展示的是多个子解析器的使用方式,细节就不用我多讲啦。
# python# command.pyimport argparsedef run_scan(args): print('run_scan', args.p, args.l)def run_aparser(args): print('run_aparser', args.p)def run_analyse(args): print('run_analyse', args.load)class Command: def __init__(self): self.parser = argparse.ArgumentParser(description='x2openEuler tool chain') self.subparser = self.parser.add_subparsers(description='subcommand parser') self.scan_parser = self.subparser.add_parser('scan', help='Migration assessment tool') self.aparser = self.subparser.add_parser('collect-conf-info', help='aparser tool') self.conf_analyse = self.subparser.add_parser('conf-analyse', help='analyse system configures and generate report') self.add_args() self.set_func() def add_args(self): self.parser.add_argument('-v', '--version', action='version', version='0.1.0 beta', help='Display version') # add_argument 中参数不加 - 的话表示位置参数, self.scan_parser.add_argument('p', help='Specify the path of scan') self.scan_parser.add_argument('-l', choices=['auto', 'c', 'python', 'java'], help='Select the language of scan') self.aparser.add_argument('p', help='Specify the path of file_dir') group = self.conf_analyse.add_mutually_exclusive_group() # 创建一个互斥组。 argparse 将会确保互斥组中只有一个参数在命令行中可用 group.add_argument('-local', action='store_true', help='analyse local system configures and generate report') group.add_argument('-load', help='analyse custom system configures and generate report') def set_func(self): # python3 command.py scan /root/lukaiyi/ttt/python3-pandas-0.25.3-1.oe1.aarch64.rpm -l python self.scan_parser.set_defaults(func=run_scan) # python3 command.py collect-conf-info /root/lukaiyi/ttt/test self.aparser.set_defaults(func=run_aparser) self.conf_analyse.set_defaults(func=run_analyse) def exec_func(self): args = self.parser.parse_args() # 当然,测试的时候可以自己构造参数列表,不用非得从命令行传参过去的 # args = self.parser.parse_args(args=['scan', 'path', '-l', 'python']) args.func(args)if __name__ == '__main__': Command().exec_func()
后来发现,这个 nargs 真的是太好用啦(其他的目前倒还没仔细研究过),它竟然能够给位置参数设置默认值(很屌的,有点颠覆了我的认知,我原先以为就可选参数是可以设置默认值的)。
没设置 nargs 的时候是这样子:
from argparse import ArgumentParserparser = ArgumentParser(description='Test')parser.add_argument("command", help="the command to be executed", choices=["dump", "delete", "update", "set"], default="set")args = parser.parse_args()print(args.command)
C:\Users\lukaiyi\insight-tool>python test.py deletedeleteC:\Users\lukaiyi\insight-tool>python test.pyusage: test.py [-h] {dump,delete,update,set}test.py: error: the following arguments are required: command
我本来想的是如果位置参数没写的话,会给我把默认值 set 返回来,结果偏偏不给我面子。
但是加上 nargs='?' 就不一样啦(这个时候位置参数就算没写,也可以直接使用给定的默认值):
nargs='?'
from argparse import ArgumentParserparser = ArgumentParser(description='Test')parser.add_argument("command", help="the command to be executed", choices=["dump", "delete", "update", "set"], nargs='?', default="set")args = parser.parse_args()print(args.command)
C:\Users\lukaiyi\insight-tool>python test.pysetC:\Users\lukaiyi\insight-tool>python test.py deletedeleteC:\Users\lukaiyi\insight-tool>python test.py delete updateusage: test.py [-h] [{dump,delete,update,set}]test.py: error: unrecognized arguments: update
也有使用 nargs='*' 和 nargs='+' 的,看起来和正则表达式中的 ? * + 比较像(实际上含义也确实比较像)。
nargs='?' 表示这个位置参数可设置零个或一个;nargs='*' 表示这个位置参数可设置零个或多个;nargs='+' 表示这个位置参数可设置一个或多个。如果还是不清楚的话可以看看下面的例子。
nargs='*'
from argparse import ArgumentParserparser = ArgumentParser(description='Test')parser.add_argument("command", help="the command to be executed", choices=["dump", "delete", "update", "set"], nargs='*', default="set")args = parser.parse_args()print(args.command)
C:\Users\lukaiyi\insight-tool>python test.pysetC:\Users\lukaiyi\insight-tool>python test.py delete['delete']C:\Users\lukaiyi\insight-tool>python test.py delete update['delete', 'update']
nargs='+'
from argparse import ArgumentParserparser = ArgumentParser(description='Test')parser.add_argument("command", help="the command to be executed", choices=["dump", "delete", "update", "set"], nargs='+', default="set")args = parser.parse_args()print(args.command)
C:\Users\lukaiyi\insight-tool>python test.pyusage: test.py [-h] {dump,delete,update,set} [{dump,delete,update,set} ...]test.py: error: the following arguments are required: commandC:\Users\lukaiyi\insight-tool>python test.py delete['delete']C:\Users\lukaiyi\insight-tool>python test.py delete update['delete', 'update']
当然,argparse 无疑还是强大的, docopt 则是通过定义帮助信息来定义命令行的,它能够根据命令行程序中定义的接口描述,来自动生成解析器!
"""Num accumulator.Usage: cmd.py [--sum]... cmd.py (-h | --help)Options: -h --help Show help. --sum Sum the nums (default: find the max)."""from docopt import docoptarguments = docopt(__doc__, options_first=True)print(arguments)
其中的 __doc__ 就是文档字符串,比较好理解,也就是 py 文件里边三引号括起来的那一坨。
root@master ~/insight-tool# python3 cmd.py --sum 1 2 3{'--help': False, '--sum': True, '': ['1', '2', '3']}root@master ~/insight-tool# python3 cmd.py 1 2 3{'--help': False, '--sum': False, ' ': ['1', '2', '3']}
来个完整的例子
# cmd.py# 1. 定义接口描述"""Num accumulator.Usage: cmd.py [--sum]... cmd.py (-h | --help)Options: -h --help Show help. --sum Sum the nums (default: find the max)."""from docopt import docopt# 2. 解析命令行arguments = docopt(__doc__, options_first=True)# 3. 业务逻辑nums = (int(num) for num in arguments[' '])if arguments['--sum']: result = sum(nums)else: result = max(nums)print(result)
root@master ~/insight-tool# python3 cmd.py --sum 1 2 36root@master ~/insight-tool# python3 cmd.py 1 2 33
usage:
(大小写不敏感)和一个可见的空行之间的文本内容会被解释为一个个使用模式。useage:
后的第一个词会被解释为程序的名称,比如下面的 cmd。"""Num accumulator.Usage: cmd cmd [--sum]... cmd (-h | --help)Options: -h --help Show help. --sum Sum the nums (default: find the max)."""
位置参数:
使用 <
和 >
包裹的参数会被解释为位置参数。
"""Usage: cli"""from docopt import docoptarguments = docopt(__doc__)# arguments = docopt(__doc__, argv=['1', '2']) argv 可以自己设定print(arguments)
root@master ~/insight-tool# python3 cmd.py 2 1{'': '2', ' ': '1'}root@master ~/insight-tool# python3 cmd.py 1 2{' ': '1', ' ': '2'}
选项参数:
以单个破折号(-
)开头的的参数为短选项,以双破折号(--
)开头的参数为长选项。
-abc
等价于 -a
、-b
和 -c
空格
或 =
指定,比如 --input ARG
等价于 --input=ARG
空格
指定,比如 -f FILE
等价于 -fFILE
"""Usage: cli [options]Options: -n, --name NAME Set name."""from docopt import docoptarguments = docopt(__doc__, argv=['-n', 'Eric'])print(arguments)arguments = docopt(__doc__, argv=['-nEric'])print(arguments)arguments = docopt(__doc__, argv=['--name', 'Eric'])print(arguments)arguments = docopt(__doc__, argv=['--name=Eric'])print(arguments)
root@master ~/insight-tool# python3 cmd.py{'--name': 'Eric'}{'--name': 'Eric'}{'--name': 'Eric'}{'--name': 'Eric'}
命令:
这里的命令也就是 argparse
中嵌套解析器所要完成的事情,准确的说,对整个命令行程序来说,实现的是子命令。在 docopt
中,凡是不符合 --options
或 <arguments>
约定的词,均会被解释为子命令。
在下面这个例子中,我们支持 create
和 delete
两个子命令,用来创建或删除指定路径。而 delete
命令支持 --recursive
参数来表明是否递归删除指定路径:
"""Usage: cli create cli delete [--recursive]Options: -r, --recursive Recursively remove the directory."""from docopt import docoptarguments = docopt(__doc__)print(arguments)
root@master ~/insight-tool# python3 cmd.py create{'--recursive': False, 'create': True, 'delete': False}root@master ~/insight-tool# python3 cmd.py delete{'--recursive': False, 'create': False, 'delete': True}root@master ~/insight-tool# python3 cmd.py delete -r{'--recursive': True, 'create': False, 'delete': True}
可选元素: [optional elements]
以中括号“[]”包裹的元素(选项、参数和命令)均会被标记为可选。多个元素放在一对中括号中或各自放在中括号中是等价的。比如:
Usage: cli [command --option]
等价于:
Usage: cli [command] [--option] []
例如上例中的 [--recursive] 便是可选项。
必填元素: (required elements)
没被中括号“[]”包裹的所有元素默认都是必填的。但有时候使用小括号“()”将元素包裹住,用以标记必填是有必要的。
比如,要将多个互斥元素进行分组:Usage: my_program (--either-this| )
另一个例子是,当出现一个参数时,也要求提供另一个参数,那么就可以这么写:
Usage: my_program [()]
这个例子中,<one-argument>
和 <another-argument>
要么都出现,要么都不出现。
互斥参数: element|another
在 argparse
中要想实现互斥参数,还需要先调用 parser.add_mutually_exclusive_group()
添加互斥组,再在组里添加参数。而在 docopt
中就特别简单,直接使用 |
进行分隔:
Usage: my_program go (--up | --down | --left | --right)
在上面的示例中,使用小括号“()”来对四个互斥选项分组,要求必填其中一个选项。
Usage: my_program go [--up | --down | --left | --right]
在上面的示例中,使用中括号“()”来对四个互斥选项分组,可以不填,或填其中一个选项。
选项简写: [options]
“[options]”用于简写选项,比如下面的示例中定义了 3 个选项:
Usage: my_program [--all --long --human-readable]--all List everything.--long Long output.--human-readable Display in human-readable format.
可简写为(也即用 [options] 代表所有可选项):
Usage: my_program [options]--all List everything.--long Long output.--human-readable Display in human-readable format.
ruby 的解析就更简单了,一看便懂,就更不用多说了。
# Rubyrequire 'optparse'options = {}opt_parser = OptionParser.new do |opts| opts.banner = 'here is help messages of the command line tool.' opts.separator '' opts.separator 'Specific options:' opts.separator '' options[:switch] = false opts.on('-s', '--switch', 'Set options as switch') do options[:switch] = true end opts.on('-n NAME', '--name Name', 'Pass-in single name') do |value| options[:name] = value end opts.on('-a A,B', '--array A,B', Array, 'List of arguments') do |value| options[:array] = value end opts.on_tail('-h', '--help', 'Show this message') do puts opts exit endendopt_parser.parse!(ARGV)puts options.inspect
[root@master ruby_learning]# ./test.rb -hhere is help messages of the command line tool.Specific options: -s, --switch Set options as switch -n, --name Name Pass-in single name -a, --array A,B List of arguments -h, --help Show this message[root@master ruby_learning]# ./test.rb -a hello,world{:switch=>false, :array=>["hello", "world"]}[root@master ruby_learning]# ./test.rb -s -a hello,world{:switch=>true, :array=>["hello", "world"]}[root@master ruby_learning]# ./test.rb -s -n looking -a hello,world{:switch=>true, :name=>"looking", :array=>["hello", "world"]}
转载地址:http://snjqi.baihongyu.com/