博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python 和 Ruby 的命令行参数解析
阅读量:4229 次
发布时间:2019-05-26

本文共 12440 字,大约阅读时间需要 41 分钟。

Python

optparse

# 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

据说 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']

docopt

当然,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

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/

你可能感兴趣的文章
.NET Framework Solutions: In Search of the Lost Win32 API
查看>>
Linux for Embedded and Real-Time Applications
查看>>
Refactoring in Large Software Projects : Performing Complex Restructurings Successfully
查看>>
Semantic Web Technologies : Trends and Research in Ontology-based Systems
查看>>
Linux All-in-One Desk Reference For Dummies
查看>>
Security Patterns : Integrating Security and Systems Engineering
查看>>
Cross-Platform Web Services Using C# & JAVA
查看>>
UML Xtra-Light: How to Specify Your Software Requirements
查看>>
Fundamentals of OOP and Data Structures in Java
查看>>
C++ Network Programming, Vol. 1: Mastering Complexity with ACE and Patterns
查看>>
The Ethical Hack: A Framework for Business Value Penetration Testing
查看>>
Agile Development with ICONIX Process: People, Process, and Pragmatism
查看>>
Practical Guide to Software Quality Management
查看>>
Real Process Improvement Using the CMMI
查看>>
GDI+ Programming in C# and VB .NET
查看>>
Implementing and Integrating Product Data Management and Software Configuration Management
查看>>
Software Configuration Management
查看>>
Agile Project Management: How to Succeed in the Face of Changing Project Requirements
查看>>
MySQL Bible
查看>>
Palm OS Programming Bible
查看>>