当前位置: 首页 > 后端技术 > Python

如何优雅地解析命令行选项

时间:2023-03-25 19:29:42 Python

如何优雅地解析命令行选项随着我们编程经验的增长,对命令行的熟悉程度越来越深,很多人会逐渐体会到使用命令行选项带来的高效命令行。自然地,我们自己编写的很多程序(或者简称为脚本)也希望像原生命令和其他程序一样,可以通过运行时输入的参数来设置和改变程序的行为;配置文件,然后定位到对应的内容,修改,保存,退出……想想就很麻烦好吗?1.手动解析那么我们开始解析命令行参数吧~我们在上一篇关于modules的文章中提到,通过变量sys.args保存了调用当前脚本时传入的命令行参数。我们先观察这个变量:#test_sys.pyimportsysprint(sys.argv)通过命令行调用:$pythontest_sys.py-dtoday-tnow--authorjustdopython--countryChina--auto得到如下输出:['test_sys.py','-d','今天','-t','现在','--author','justdopython','--country','中国','--auto']可以看出,sys.argv实际上是将命令行参数用空格分割得到的字符串列表。此外,第一个命令行参数是当前运行脚本的名称。如果我们要提取每个参数及其对应的值,首先要区分命令行的长参数和短参数,分别以“--”和“-”开头来标识。所以我们也以此作为判断长短参数的条件:importsysforcommand_arginsys.argv[1:]:ifcommand_arg.startswith('--'):print("%s是长参数"%command_arg)elif命令参数。startswith('-'):print("%s是一个短参数"%command_arg)测试结果:$pythonmanually_parse_argv.py-dtoday-tnow--authorjustdopython--countryChina--auto-d是一个短参数parameter-t为短参数--author为长参数--country为长参数--auto为长参数接下来我们需要在解析出长短参数的基础上,分析对应的参数值:#manually_parse_argv.pyimportsys#由于sys.argv的第一个变量是当前脚本的名字,所以跳过index,command_arginenumerate(sys.argv[1:]):ifcommand_arg.startswith('--'):try:value=sys.argv[1:][index+1]ifnotvalue.startswith('-'):print("%s是长参数,参数值为%s"%(command_arg,value))继续exceptIndexError:passprint("%sisalongparameter,noparametervalue"%command_arg)elifcommand_arg.startswith('-'):try:value=sys.argv[1:][index+1]ifnotvalue.startswith('-'):print("%s是短参数,参数值为%s"%(command_arg,value))continueexceptIndexError:passprint("%s是短参数,noparametervalue"%command_arg)再测试一下:$pythonmanually_parse_argv.py-dtoday-tnow--authorjustdopython--countryChina--auto-d是一个短参数,参数值为today-t是一个short参数,且参数值为now--author为长参数,参数值为justdopython--country为长参数,参数值为China--auto为长参数,无参数值好看但看再次atourcode...真正的逻辑还没有开始,已经写了几十行代码来解析命令行参数。这根本不是pythonic——并且不包括一些其他的异常处理。更有什者,每一个类似的程序都需要加入这样的程序。2.getopt模块可以帮助你。Python的优势就是生态太丰富了。几乎每个你想用的函数都已经有人为你写好供你调用。除了梦到衣来伸手饭来张嘴的日子,用Python写程序也不是不可以梦到。例如在命令行参数的解析中,有一个名为getopt的模块,可以准确区分长短命令行参数,也可以正确提取命令行参数的值。我们先来看看:#test_getopt.pyimportsysimportgetoptopts,args=getopt.getopt(sys.argv[1:],'d:t:',["author=","country=","auto"])print(opts)print(args)打印结果:$pythontest_getopt.py-dtoday-tnow--authorjustdopython--countryChina--auto[('-d','today'),('-t','now'),('--author','justdopython'),('--country','China'),('--auto','')][]下面解释一下相关的含义参数。getopt模块中的getopt函数用于解析命令行参数。该函数接受三个参数:args、shortopts和longopts,分别代表“命令行参数”、“接收的短选项”和“接收的长选项”。其中args和longopts是字符串列表,而shortopts是一个字符串。同样,由于sys.argv的第一个值是当前脚本的名称,因此大多数情况下我们会选择将sys.argv[1:]的值传递给args参数。shortopts参数接受的字符串表示需要解析哪些短选项。字符串中的每个字母代表一个短选项:importsysimportgetoptopts,args=getopt.getopt(sys.argv[1:],'dt')print(opts)print(args)output:$pythontest_getopt.py-d-t[('-d',''),('-t','')][]当然,如果输入参数少的话,也不会造成解析失败:$pythontest_getopt.py-t[('-t','')][]但是如果给了一个意外的参数,就会导致模块抛出错误:$pythontest_getopt.py-d-t-kTraceback(mostrecentcalllast):File“test_getopt.py”,第11行,在opts中,args=getopt.getopt(sys.argv[1:],'dt')...raiseGetoptError(_('option-%snotrecognized')%opt,opt)getopt.GetoptError:option-knotrecognized这个处理逻辑也很符合我们使用命令的经验,可以简单理解为“宁缺毋滥”。如果短参数对应的字母后面有冒号:,表示该参数需要指定一个参数值。getopt会使用参数对应的下一个命令行参数作为参数值(不管下一个参数的形式):importsysimportgetoptopts,args=getopt.getopt(sys.argv[1:],'d:t')print(opts)print(args)#$pythontest_getopt.py-d-t#[('-d','-t')]#[]此外,一旦getopt没有在预期的位置找到多头和空头选项接收到以“--”或“-”开头的字符串将终止解析过程,剩余未解析的字符串将在返回的元组的第二项中返回。$pythontest_getopt.py-dd_valueo--pattern-t[('-d','d_value')]['o','--pattern','-t']同样,longopts参数表示需要parsed长参数。列表中的每个字符串代表一个长参数:importsysimportgetoptopts,args=getopt.getopt(sys.argv[1:],'',["author","country"])print(opts)print(args)#$pythontest_getopt.py--author--country#[('--author',''),('--country','')]#[]解析带有参数值的长参数,一个等号(=)也应该附加到每个长参数以表明该参数需要有一个值:importsysimportgetoptopts,args=getopt.getopt(sys.argv[1:],'',["author=","country"])print(opts)print(args)#$pythontest_getopt.py--authorjustdopython--country#[('--author','justdopython'),('--country','')]#[]于是终于得到了我们开始的分析结果:importsysimportgetoptopts,args=getopt.getopt(sys.argv[1:],'d:t:',["author=","country=","auto"])print(opts)print(args)#$pythontest_getopt.py-dtoday-tnow--authorjustdopython--countryChina--auto#[('-d','today'),('-t','now'),('--author','justdopython'),('--country','中国na'),('--auto','')]#[]解析完成后,我们就可以从opts中提取对应的值了。懒人福音getopt不仅可以省去我们编写命令行参数解析代码的时间和精力,还可以让你在输入命令行参数时省去几个字母——当然,严格来说,我们不推荐这样的行为。慎用,慎用!getopt支持前缀匹配来解析长参数。只要输入参数能唯一匹配到指定参数,也能完成预期的解析。$pythontest_getopt.py-dtoday-tnow--authjustdopython--counChina--auto[('-d','today'),('-t','now'),('--author','justdopython'),('--country','China'),('--auto','')][]可以看到我们只输入了作者和国家的部分参数,但是getopt还是正确解析。小结本文讲解两种使用Python解析命令行参数的方法,一种是稍微繁琐的手动解析,即编写程序自定义解析;另一种是调用现成的更健壮的getopt模块来完成解析。从此,我们终于可以摆脱繁琐的配置文件,优雅简洁地修改程序的行为。以上就是本次分享的全部内容。想了解更多python知识,请前往公众号:Python编程学习圈,发“J”免费领取,每日干货分享