Bash
getopt、getopts 或手動解析 - 當我想同時支持短選項和長選項時使用什麼?
目前我正在編寫一個具有以下要求的 Bash 腳本:
- 它應該在各種各樣的 Unix/Linux 平台上執行
- 它應該支持短選項和(GNU)長選項
我知道這
getopts
將是可移植性方面的首選方式,但 AFAIK 它不支持長選項。
getopt
支持長選項,但BashGuide強烈反對它:永遠不要使用 getopt(1)。getopt 無法處理空參數字元串或帶有嵌入空格的參數。請忘記它曾經存在過。
因此,仍然有手動解析的選項。這很容易出錯,產生了相當多的樣板程式碼,我需要自己處理錯誤(我想自己
getopt(s)
做錯誤處理)。那麼,在這種情況下,什麼是首選呢?
如果它必須可移植到一系列 Unices,則必須堅持使用 POSIX sh。AFAIU 那裡你別無選擇,只能手動滾動參數處理。
getopt
vsgetopts
似乎是一個宗教問題。至於Bash FAQgetopt
中反對的論點:
- “
getopt
無法處理空參數字元串”似乎指的是可選參數的已知問題,它看起來getopts
根本不支持(至少從help getopts
Bash 4.2.24 的閱讀中)。來自man getopt
:getopt(3) 可以解析帶有可選參數的長選項,這些可選參數被賦予一個空的可選參數(但不能對短選項執行此操作)。此 getopt(1) 將空的可選參數視為不存在。
我不知道 “
getopt
不能處理的地方$$ … $$帶有嵌入空格的參數”來自,但讓我們測試一下:
- test.sh:
#!/usr/bin/env bash set -o errexit -o noclobber -o nounset -o pipefail params="$(getopt -o ab:c -l alpha,bravo:,charlie --name "$0" -- "$@")" eval set -- "$params" while true do case "$1" in -a|--alpha) echo alpha shift ;; -b|--bravo) echo "bravo=$2" shift 2 ;; -c|--charlie) echo charlie shift ;; --) shift break ;; *) echo "Not implemented: $1" >&2 exit 1 ;; esac done
- 跑:
$ ./test.sh - $ ./test.sh -acb ' whitespace FTW ' alpha charlie bravo= whitespace FTW $ ./test.sh -ab '' -c alpha bravo= charlie $ ./test.sh --alpha --bravo ' whitespace FTW ' --charlie alpha bravo= whitespace FTW charlie
對我來說看起來像是檢查和配對,但我相信有人會展示我是如何完全誤解了這句話的。當然,便攜性問題仍然存在;您必須決定在具有較舊或沒有可用 Bash 的平台上投入多少時間。我自己的建議是使用YAGNI和KISS指南——只為那些你知道將要使用的特定平台開發。隨著開發時間的延長,Shell 程式碼的可移植性通常會達到 100%。