Shell指令碼中引數處理方法
'getopt'與'getopts'類似,不過'getopts'只能處理短選項,'getopt'則能處理短選項和長選項。所謂的短選項就是類似下面這樣的選項:
-a
而下面這樣的則是長選項
--action=delete
當然,事無絕對,通過一些技巧,用'getopts'處理長選項也是可能的。這裡先說一下如何用'getopt'來處理引數吧。
需要事先說明的一點是,'getopt'不是Shell內建的命令,而是'util-linux'這個軟體包提供的功能,它不是POSIX標準的一部分,所以也有人建議不使用'getopt'。
首先將之前說到的五種動作對應的短選項擴充套件一下,以便講解'getopt'的使用:
- -d/–delete : 將檔案移動到回收站,該選項後需要指定一個檔案或目錄名
- -l/–list : 列出被移動到回收站的檔案及其id,該選項不需要值
- -b/–back : 恢復被移動到回收站的檔案,該選項需要指定一個檔案對應的id
- -c/–clear : 清空回收站,該選項不需要值
- -h/–help : 列印幫助資訊
'getopt'既能處理短選項也能處理長選項,短選項通過引數-o指定,長選項通過引數-l指定。同'getopts'一樣,它一次也只解析一個選項,所以也需要迴圈處理,不過與'getopts'不同的是,'getopt'沒有使用OPTIND和OPTARG這兩個變數,所以我們還得手動對引數進行'shift',對需要值的選項,也得手動去取出值。
下面是在Shell中使用'getopt'的一個示例:
可以看到,'getopt'將引數中以下形式的內容:
--longopt=argument
在返回結果中替換成下面這樣的形式:
--longopt argument
這樣就可以通過迴圈和'shift'來進行處理了,不過在指令碼中,'shift'命令是對命令列引數起作用的,即特殊變數"[email protected]",而我們在指令碼中只能將'getopt'的返回結果作為字串儲存到一個變數中。為了讓'shift'起作用,通常還要使用'set'命令來將變數的值賦給"[email protected]"這個特殊變數。
真是有夠麻煩的……算了,下面再集中吐槽吧……
然後,在設定好短選項和長選項後,在將實際的引數傳給'getopt'時,要在實際引數前加上一個兩個連字元--,而'getopt'會將這兩個連字元放到返回結果的最後面,在處理時可以將這兩個連字元視為結束標誌。
以下是針對本文假設的情景,使用'getopt'解析引數的流程:
arg=$(getopt -o d:lb:ch -l delete:,list,back:,clear,help -- $@) set -- "$arg" while true do case $1 in -d|--delete) file_to_trash=$2 trash $file_to_trash # trash is a function shift 2 ;; -l|--list) print_trashed_file # print_trashed_file is a function shift ;; -b|--back) file_to_untrash=$2 untrash $file_to_untrash # untrash is a function shift ;; -c|--clear) clean_all # clean all is a function shift ;; -h|--help) usage exit 0 ;; --) shift break ;; esacdone
然而,知道了'getopt'的使用及其原理後,自然而然地可以發現,我可以不用去管這個結束標誌,用"$#"這個表示引數個數的特殊變數,同樣可以控制引數解析的流程,這完全和手工解析是同一個道理。我甚至可以將'getopt'的返回結果儲存到一個數組裡,直接迴圈處理這個陣列,而不用使用'set'命令了。
好了,吐槽時間。
我之前寫指令碼都是用的'getopts',一來我用不上長選項,二來'getopts'的使用足夠簡單。在寫本文之前,我倒是知道'getopt'可以處理長選項,但沒仔細瞭解過。這兩天瞭解了一下,覺得還是別用'getopt'的好,理由如下:
- 'getopt'不是Shell內建命令,跨平臺使用時可能會出現問題;
-
只是將'–longopt=val'這樣的引數形式替換成了'–longopt val',但因此增加了許多複雜性,比如使用了'set'命令,在使用'set'命令時還要考慮'getopt'的返回結果中有無Shell命令,有的話應該使用'eval'命令來消除可能導致的錯誤
eval set -- "$arg"
- 呼叫完還要進行與手工解析類似的工作,相比手工解析,並沒有多大優勢;
- 真的需要長選項嗎?我覺得短選項就足夠了