網站首頁 編程語言 正文
如何優雅地解析命令行選項
隨著我們編程經驗的增長,對命令行的熟悉程度日漸加深,想來很多人會漸漸地體會到使用命令行帶來的高效率。
自然而然地,我們自己寫的很多程序(或者干脆就是腳本),也希望能夠像原生命令和其他程序一樣,通過運行時輸入的參數就可以設定、改變程序的行為;而不必一層層找到相應的配置文件,然后還要定位到相應內容、修改、保存、退出……
想想就很麻煩好嗎
1. 手動解析
所以讓我們開始解析命令行參數吧~
在以前關于模塊的文章中我們提到過sys.args這個變量,其中保存的就是調用當前腳本時傳入的命令行參數。
我們先觀察一下這個變量:
# test_sys.py
import sys
print(sys.argv)
通過命令行調用:
$ python test_sys.py -d today -t now --author justdopython --country China --auto
得到如下輸出結果:
['test_sys.py', '-d', 'today', '-t', 'now', '--author', 'justdopython', '--country', 'China', '--auto']
可見,sys.argv其實就是將命令行參數按空格切分,得到的一個字符串列表。此外,命令行參數的第一個就是當前運行的腳本名稱。
我們如果想要提取出各個參數及其對應的值,首先得區分出命令行的長參數和短參數,它們分別由“--”和“-”開頭作為標識。所以我們也以此作為判斷長短參數的條件:
import sys
for command_arg in sys.argv[1:]:
if command_arg.startswith('--'):
print("%s 為長參數" % command_arg)
elif command_arg.startswith('-'):
print("%s 為短參數" % command_arg)
測試結果:
$ python manually_parse_argv.py -d today -t now --author justdopython --country China --auto
-d 為短參數
-t 為短參數
--author 為長參數
--country 為長參數
--auto 為長參數
緊接著,我們需要在解析出長短參數這一步的基礎上,再解析出對應的參數值:
# manually_parse_argv.py
import sys
# 由于sys.argv的第一個變量是當前腳本名稱,因此略過
for index, command_arg in enumerate(sys.argv[1:]):
if command_arg.startswith('--'):
try:
value = sys.argv[1:][index+1]
if not value.startswith('-'):
print("%s 為長參數,參數值為 %s" % (command_arg, value))
continue
except IndexError:
pass
print("%s 為長參數,無參數值" % command_arg)
elif command_arg.startswith('-'):
try:
value = sys.argv[1:][index+1]
if not value.startswith('-'):
print("%s 為短參數,參數值為 %s" % (command_arg, value))
continue
except IndexError:
pass
print("%s 為短參數,無參數值" % command_arg)
再測試一下:
$ python manually_parse_argv.py -d today -t now --author justdopython --country China --auto
-d 為短參數,參數值為 today
-t 為短參數,參數值為 now
--author 為長參數,參數值為 justdopython
--country 為長參數,參數值為 China
--auto 為長參數,無參數值
看起來還不錯。
但是再看看我們的代碼……真正的邏輯還沒開始,反倒是為了解析命令行參數已經寫了幾十行代碼。這一點都不pythonic——這還不包括一些其他關于異常情況的處理。
更何況是要在每個類似的程序中加入這么一段程序了。
2. getopt模塊
Python的好處就在于,生態過于豐富,幾乎你要用到的每個功能,都已經有人為你寫好了現成的模塊以供調用。
衣來伸手飯來張口的日子除了能在夢中想想,在用Python寫程序的時候也不是不可以奢望。
比如命令行參數解析,就有一個名為getopt的模塊,既能夠準確區分長短命令行參數,也能夠恰當地提取命令行參數的值。
咱們先來看看:
# test_getopt.py
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], 'd:t:', ["author=", "country=", "auto"])
print(opts)
print(args)
打印結果:
$ python test_getopt.py -d today -t now --author justdopython --country China --auto
[('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')]
[]
下面我們來分別解釋一下相關參數的含義。
getopt模塊中的getopt函數用于解析命令行參數。
該函數接受三個參數:args,shortopts和longopts,分別代表“命令行參數”,“要接收的短選項”和“要接收的長選項”。
其中args和longopts均為字符串組成的列表,而shortopts則為一個字符串。
同樣地,由于sys.argv的第一個值為當前腳本名稱,所以多數情況下我們會選擇向args參數傳入sys.argv[1:]的值。
而shortopts這個參數接受的字符串則表示需要解析哪些短選項,字符串中每個字母均表示一個短選項:
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], 'dt')
print(opts)
print(args)
輸出結果:
$ python test_getopt.py -d ?-t
[('-d', ''), ('-t', '')]
[]
當然,如果輸入的參數少于預期,也不會導致解析失敗:
$ python test_getopt.py ?-t
[('-t', '')]
[]
但要是給出了預期之外的參數,就會導致模塊拋錯:
$ python test_getopt.py -d -t -k
Traceback (most recent call last):
File "test_getopt.py", line 11, in <module>
opts, args = getopt.getopt(sys.argv[1:], 'dt')
...
raise GetoptError(_('option -%s not recognized') % opt, opt)
getopt.GetoptError: option -k not recognized
這樣的處理邏輯也符合我們使用命令的體驗,可以簡單地理解為“寧缺毋濫”。
如果短參數相應的字母后帶了一個冒號:,則意味著這個參數需要指定一個參數值。getopt會將該參數對應的下一個命令行參數作為參數值(而不論下一個參數是什么形式):
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], 'd:t')
print(opts)
print(args)
# $ python test_getopt.py -d -t
# [('-d', '-t')]
# []
此外,一旦getopt在預期接收到長短選項的位置沒有找到以“--”或“-”開頭的字符串,就會終止解析過程,剩下的未解析字符串均放在返回元組的第二項中返回。
$ python test_getopt.py -d d_value o --pattern -t
[('-d', 'd_value')]
['o', '--pattern', '-t']
類似地,longopts參數表示需要解析的長參數。
列表中的每一個字符串代表一個長參數:
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], '', ["author", "country"])
print(opts)
print(args)
# $ python test_getopt.py --author --country
# [('--author', ''), ('--country', '')]
# []
要解析帶有參數值的長參數,還應在每個長參數后附帶一個等于號(=),以標識該參數需要帶值:
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], '', ["author=", "country"])
print(opts)
print(args)
# $ python test_getopt.py --author justdopython --country
# [('--author', 'justdopython'), ('--country', '')]
# []
所以最終就得到了我們一開始的解析結果:
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], 'd:t:', ["author=", "country=", "auto"])
print(opts)
print(args)
# $ python test_getopt.py -d today -t now --author justdopython --country China --auto
# [('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')]
# []
解析完成后,我們再從opts中提取相應的值即可。
懶人福音
getopt除了替我們節省了編寫命令行參數解析代碼的時間和精力,另一方面還可以讓你在輸入命令行參數時少打幾個字母——當然,嚴謹來講,我們并不建議此類行為。慎用,慎用!
getopt對長參數的解析支持前綴匹配,只要輸入的參數能夠與某個指定參數唯一匹配,同樣能夠完成預期解析。
$ python test_getopt.py -d today -t now --auth justdopython --coun China --auto
[('-d', 'today'), ('-t', 'now'), ('--author', 'justdopython'), ('--country', 'China'), ('--auto', '')]
[]
可以看到,author和country兩個參數我們都只輸入了一部分,但是getopt依然進行了正確的解析。
總結
本文講解了使用Python解析命令行參數的兩種方式,一種是略顯笨重的手動解析,即自己編寫程序自定義解析;另一種則是調用現成、且更加健壯的getopt模塊來完成解析。
從此以后,我們終于可以擺脫繁瑣的配置文件,用一種優雅簡潔的方式來修改程序的行為了。
原文鏈接:https://juejin.cn/post/7108908752174579743
- 上一篇:Qt編寫顯示密碼強度的控件_C 語言
- 下一篇:QT生成隨機驗證碼的方法_C 語言
相關推薦
- 2022-07-21 Error: rsync: [sender] safe_read failed to read 4
- 2023-04-26 C++變量初始化形式及其默認初始值問題_C 語言
- 2022-09-25 自動微分----pytorch中的梯度運算與反向傳播函數(預備知識)
- 2022-05-06 mac goland 常用快捷鍵
- 2023-04-07 關于vector的常見用法詳解_C 語言
- 2022-05-24 Flutter滾動組件之ListView使用方法詳解_Android
- 2022-04-11 springboot上傳文件到Nginx代理的FTP文件服務器
- 2022-10-31 Android虛擬機與類加載機制詳情_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支