起因:最近我在用Python做了一个随机大小写的脚本,由于第一次涉及命令行程序的编写,走了很多弯路,并没有使用 argparse 的这样nb的第三方库,就自己撸了一个参数解析,好在最后完成了!
项目地址:up-low-letter
如果喜欢喵,给个star吧喵(战术去世.jpg)
注意:本人对Python的理解不深,这次刚完成一个项目,感想颇多,写一个文章总结一下做个笔记,方便以后复习,如果出现错误,大佬请轻喷 ,欢迎在评论区指正,谢谢!
可以argparse这样的大的第三方库,不用这样搞。这里是因为走了弯路,就把思路写出来了
如果你正在学argparse等高级东西,请绕行,这篇文章在浪费你的时间
argv的使用 大佬可以直接跳到下一段落
sys模块是与python解释器交互的一个接口。sys 模块提供了许多函数和变量来处理 Python 运行时环境的不同部分。
首先,请导入模块(废话)
在python脚本被执行的时候,sys.argv列表中就会存着运行时的参数,如:
1 ['test.py','arg1','arg2','arg3']
由此观之:
sys.argv[0] 表示程序自身的名称 sys.argv[1] 表示程序的第一个参数 sys.argv[2] 表示程序的第二个参数
网上流传过这样一个事:
一个用爱发电的免费加速器作者,发现有奸商把他的软件加了壳去某宝上卖,他把软件加壳、资源混淆搞了一路十三招,还是有人拿去卖,最后没有办法直接连文件名改掉都不让运行。在这里,我们也可以达到这样的效果:
1 2 3 4 5 6 7 8 9 10 11 12 import sysif sys.argv[0 ] != 'test.py' : print (f'你下到假传奇了:{sys.argv[0 ]} ' ) sys.exit(0 ) else : print (f'恭喜你,你下到了真传奇:{sys.argv[0 ]} ' ) print ('汤碗拦月loding......' )print ('大扎好,我系轱天乐,我四渣渣辉,汤碗拦月,介四里没有挽过的船新版本,挤需体验三番钟,里造会干我一样,爱象节款游戏。' )
运行结果:
1 2 3 4 5 6 7 8 9 ------------名字为test.py------------ $ python test.py 恭喜你,你下到了真传奇:test.py 汤碗拦月loding...... 大扎好,我系轱天乐,我四渣渣辉,汤碗拦月,介四里没有挽过的船新版本,挤需体验三番钟,里造会干我一样,爱象节款游戏。 ------------名字为flase.py------------ $ mv test.py flase.py $ python flase.py 你下到假传奇了:flase.py
好样的,我们已经帮助用户判断是否他的传奇是真传奇了,是不是成就感满满?(逃)
实战 我们现在已经初步了解了argv的用法了,现在开始实战:
我们要做一个类似cat
命令的功能,预计的输出:
1 2 3 4 5 $ ls flag.txt $ python cat.py flag.txt Hi,here! There is't a flag,Find it in the folder root
分析 从输出可以看出,程序直接读取运行脚本时的第一个参数(继文件名的第一个参数,sys.argv的第二个参数)作为路径读取文件并输出
实现 1 2 3 4 5 6 import syspath = sys.argv[1 ] with open (path, 'r' ) as f: cont = f.read() print (cont)
使用argv来枚举 我们得到了argv这个大杀器,现在我们可以搞点事了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import sysdef gethelp (): print ("帮助信息\nNO INFO" ) def example1 (parm ): print (f'ex1:{parm} ' ) def example2 (parm ): print (f'ex2:{parm} ' ) if len (sys.argv) == 1 : gethelp() target = sys.argv[1 ] if target == '-h' : gethelp() elif target == '-ex1' : example1(sys.argv[2 ]) elif target == '-ex2' : example2(sys.argv[2 ]) else : print (f'No such parm:{sys.argv[2 ]} ' )
如果你想写全称,就这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import sysdef gethelp (): print ("帮助信息\nNO INFO" ) def example1 (parm ): print (f'ex1:{parm} ' ) def example2 (parm ): print (f'ex2:{parm} ' ) if len (sys.argv) == 1 : gethelp() target = sys.argv[1 ] if target == '-h' or target == '--help' : gethelp() elif target == '-ex1' or target == '--example1' : example1(sys.argv[2 ]) elif target == '-ex2' or target == '--example2' : example2(sys.argv[2 ]) else : print (f'No such parm:{sys.argv[2 ]} ' )
那看起来很棒,但会出现问题:
那怎么办? 我们尝试使用枚举的方式解决问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 target = sys.argv[1 :] for i in target: if i.startswith("-" ): key.append(i) for i in key: n = sys.argv.index(i) if i == '-h' or i == '--help' : gethelp() elif i == '-ex1' or i == '--example1' : example1(sys.argv[n+1 ]) elif i == '-ex2' or i == '--example2' : example2(sys.argv[n+1 ]) else : print (f'No such parm:{i} ' )
继续优化,把参数放到key_list里:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 key_list ={ "-ex1" : example1, "--example1" : example1, "-ex2" : example2, "--example2" : example2, } target = sys.argv[1 :] for i in target: if i.startswith("-" ): key.append(i) for i in key: n = sys.argv.index(i) if i == '-h' or i == '--help' : gethelp() elif i in key_list: key_list[i](sys.argv[n+1 ]) else : print (f'No such parm:{i} ' )
那么,有人就会问了:为什么把help单独提出来放到前面?那是因为直接放到key_list里,会出现访问下标越界。
当无附加参数的参数(不知道术语)较多的时候,也可以单独列个字典:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 key_list_0 ={ "-h" : gethelp, "--help" : gethelp, } key_list_1 ={ "-ex1" : example1, "--example1" : example1, "-ex2" : example2, "--example2" : example2, } target = sys.argv[1 :] for i in target: if i.startswith("-" ): k = target.index(i) for i in key: n = sys.argv.index(i) if i in key_list_0: key_list_0[i]() elif i in key_list_1: key_list_1[i](sys.argv[n+1 ]) else : print (f'No such parm:{i} ' )
当需要可选参数时,可以使用布尔值来确定是有调用可选参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 key_list_0 ={ "-h" : gethelp, "--help" : gethelp, } key_list_1 ={ "-ex1" : example1, "--example1" : example1, "-ex2" : example2, "--example2" : example2, } ex3 = False target = sys.argv[1 :] for i in target: if i.startswith("-" ): k = target.index(i) key.append(i) for i in key: n = sys.argv.index(i) if i in key_list_0: key_list_0[i]() if i in key_list_1: key_list_1[i](sys.argv[n+1 ]) elif i == '-ex3' or i == '--example3' : ex3 == True ex3_i = n else : print (f'No such parm:{i} ' ) if ex3: example3(sys.argv[ex3_i+1 ])
这样,在调用-ex3
和--example3
时,将会运行example3
方法,不使用也不会报错
这里可能会出现问题:当只使用可选参数时,她将出现问题,我们这里给她做一个排除:
1 2 3 4 5 6 7 8 9 key = [] target = sys.argv[1 :] for i in target: if i.startswith("-" ): key.append(i) if len (key) < 2 : if key == '-o' : print ("Error:不可只调用可选参数" ) sys.exit(0 )
也可以继续优化,将可选参数列为一个字典,但我并未使用到,就不作提及了。
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import sysdef gethelp (): print ("帮助信息\nNO INFO" ) def example1 (parm ): print (f'ex1:{parm} ' ) def example2 (parm ): print (f'ex2:{parm} ' ) def example3 (parm ): print (f"\n我是可选参数,ex3:{parm} " ) key_list_0 ={ "-h" : gethelp, "--help" : gethelp, } key_list_1 ={ "-ex1" : example1, "--example1" : example1, "-ex2" : example2, "--example2" : example2, } if len (sys.argv) == 1 : gethelp() key = [] ex3 = False target = sys.argv[1 :] for i in target: if i.startswith("-" ): key.append(i) for i in key: n = sys.argv.index(i) if i.startswith("-" ): key.append(i) if len (key) < 2 and '-ex3' in key: print ("Error:不可只调用可选参数" ) sys.exit(0 ) if i in key_list_0: key_list_0[i]() elif i in key_list_1: key_list_1[i](sys.argv[n+1 ]) elif i == '-ex3' or i == '--example3' : ex3 = True ex3_i = n break else : print (f'No such parm:{i} ' ) if ex3: example3(sys.argv[ex3_i+1 ])
总结 不如第三方库,学学思路就行了 ,不如argparse。