當你想用一種專業的方式解析命令行參數時,getopts就是要選擇的工具。和它的舊版本兄弟命令getopt不一樣(注意沒有s!),getopts是shell內置命令。高級地方表如今html
一些解析位置參數的其餘方法(不用getopt(s))在這裏介紹了: 如何處理位置參數.算法
注意getopts不能解析GNU風格的長選項(--myoption)或XF86風格的長選項(-myoption)!shell
須要先了解一下咱們這裏探討的事情,因此讓咱們來看一個範例… 來看一下下面這行命令:數組
mybackup -x -f /etc/mybackup.conf -r ./foo.txt ./bar.txt
全部這些都叫位置參數,可是你能夠把他們分紅一些邏輯組:bash
讓你體會一下爲何getopts頗有用: 上面的命令能夠像這樣讀取…編輯器
mybackup -xrf /etc/mybackup.conf ./foo.txt ./bar.txt
…使用本身的代碼去解析很困難。而getopts能夠認出全部常見的選項格式。函數
選項標識能夠有大小寫,也能夠是數字。甚至是其餘可識別字符,可是並不推薦這麼作(可用性差並且特殊字符可能會出問題)。工具
通常你須要調用getopts好幾回。每次會使用"下一個"位置參數(和一個可能的附加參數),若是解析成功,會給你返回結果。getopts不會改變位置參數的設定 —— 若是你想要shift掉參數,你必須手工處理:oop
shift $((OPTIND-1)) # now do something with $@
由於getopts在沒有要解析的參數剩餘時會返回退出狀態_FALSE_,因此能夠很容易的在while循環使用:測試
while getopts ...; do ... done
getopts將會解析選項和他們可能的參數。遇到第一個非選項的參數時將會中止解析(一個不以連字符(-)開頭的字符串,這不是前面任何一個選項的參數)。一樣也會在看到--(雙連字符)時中止解析,由於這個含義是選項終止。
變量 | 描述 |
---|---|
OPTIND | 保存下一個要解析的參數的指針。這就是getopts如何"記住"本身的狀態和回調請求。一樣能夠用於在getopts處理過以後shift掉位置參數。OPTIND初始爲1, 若是你想要再次使用getopts解析任何參數時須要從新設置爲1 |
OPTARG | 這個變量設置爲被getopts發現的選項的參數。一樣包含了未知的選項標記 |
OPTERR | (可選值0或1)代表Bash是否應該顯示getopts內置的錯誤信息。該值在每一個shell啓動的時候會被初始化爲1 - 因此若是你不想看到煩人的信息請務必設置爲0! |
getopts一樣使用這些變量用於錯誤報告(they're set to value-combinations which arent possible in normal operation).#括號裏面的不會翻譯,預留
getopts的基本語法是:
getopts OPTSTRING VARNAME [ARGS...]
解釋:
選項 | 說明 |
---|---|
OPTSTRING | 告訴getopts指望哪一個選項和指望的參數在哪裏(參考下面的) |
VARNAME | 告訴getopts哪一個shell變量用於選項報告 |
ARG | 告訴getopts將這些解析爲附加單詞而不是位置參數 |
option-string告訴getopts指望哪一個選項,而且哪一個選項必須有參數。語法很是簡單 -- 每一個字母就是選項名自己,下面這個範例告訴getopts尋找-f, -A和-x:
getopts fAx VARNAME
當你想讓getopts對某個選項指望一個參數時,只是在這個選項標記後面放置一個:(冒號)。若是你想讓-A指望一個參數(例如變成 -A SOMETHING),只須要:
getopts fA:x VARNAME
若是option-string首個字母是:(冒號),一般是荒謬的,由於沒有任何選項在它以前,這種狀況下,getopts會切換到"靜默錯誤報告"模式。在產品腳本中,這一般就是你想要的結果(自行抓取錯誤信息處理,不要被煩人的信息所幹擾)。
getopts工具會默認解析當前shell或函數的位置參數(意味着它解析的是"$@")。
你能夠給出你本身的一組參數解析。當附加參數在VARNAME參數以後給出時,getopts並不試圖解析這些位置參數。
用這種方式,你能夠按照你喜歡的方式解析任何選項,這裏是一個數組的範例:
while getopts :f:h opt "${MY_OWN_SET[@]}"; do ... done
不帶這些附加參數調用getopts的方式等同於顯式的使用"$@"調用:
getopts ... "$@"
關於錯誤報告,getops能夠在兩種模式下運行:
對於產品腳本我建議使用靜默模式,由於這樣看起來更專業,你不想看到更多煩人的信息。一樣也更容易處理,失敗的用例都以更簡單的方式顯示。
選項 | 說明 |
---|---|
invalid option | VARNAME is set to ? (quersion-mark) and OPTARG is unset |
required argument not found | VARNAME is set to ? (quersion-mark), OPTARG is unset and an error message is printed |
選項 | 說明 |
---|---|
invalid option | VARNAME is set to ? (question-mark) and OPTARG is set to the (invalid) option character |
required argument not found | VARNAME is set to : (colon) and OPTARG contains the option-character in question |
足夠說明一些問題!
讓咱們先看一個很是簡單的實例: 只有一個指望的選項(-a),沒有任何參數。一樣咱們用帶:(冒號)的option string爲了禁用詳盡錯誤顯示:
#!/bin/bash while getopts ":a" opt; do case $opt in a) echo "-a was triggered!" >&2 ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; esac done
我把這些內容放到一個文件go_test.sh,就是你接下來看到的範例中的名字。
來讓咱們作一些測試:
$ ./go_test.sh $
什麼都沒發生?對的,getopts沒看到任何合法或非法的選項(前面有短橫線的字母),因此不會觸發。
$ ./go_test.sh /etc/passwd $
仍是 — 什麼都沒發生。很是相似的用例: getopts沒看到任何合法或非法的選項(前面有短橫線的字母),因此不會觸發。
傳遞給你的腳本的參數固然能夠用$1 - ${N}獲取。
如今讓咱們觸發一下getopts: 提供選項。
首先,來一個非法的:
$ ./go_test.sh -b Invalid option: -b $
和預期的同樣,getopts不容許這個選項,像上面說的同樣: It placed ? into $opt and the invalid option character (b) into $OPTARG. 咱們的用例就驗證了這一點。
如今,來一個合法的(-a):
$ ./go_test.sh -a -a was triggered! $
你看到了,這個探測結果運行的很完美。在咱們的用例a選項放在了變量$opt中。
固然在調用的時候能夠組合有效和無效的選項:
$ ./go_test.sh -a -x -b -c -a was triggered! Invalid option: -x Invalid option: -b Invalid option: -c $
最後,天然也能夠屢次給出咱們的選項:
$ ./go_test.sh -a -a -a -a -a was triggered! -a was triggered! -a was triggered! -a was triggered! $
最後一個例子讓咱們須要考慮到幾點:
讓咱們把上面的例子擴展一下。只有一點點:
#!/bin/bash while getopts ":a:" opt; do case $opt in a) echo "-a was triggered, Parameter: $OPTARG" >&2 ;; \?) echo "Invalid option: -$OPTARG" >&2 exit 1 ;; :) echo "Option -$OPTARG requires an argument." >&2 exit 1 ;; esac done
讓咱們繼續作和最後一個範例一樣的測試:
$ ./go_test.sh $
像上面同樣,什麼都沒發生。就沒觸發。
$ ./go_test.sh /etc/passwd $
很是相似的狀況: 沒有觸發。
非法選項:
$ ./go_test.sh -b Invalid option: -b $
和指望的同樣,像上面同樣,getopts不容許這個選項,和程序算法吻合。
合法選項,可是不帶強制要求的參數:
$ ./go_test.sh -a Option -a requires an argument. $
選項OK,可是丟掉了一個參數。
讓咱們提供這個參數:
$ ./go_test.sh -a /etc/passwd -a was triggered, Parameter: /etc/passwd $