2010-04-27 94 views
10

我剛剛發現getopt不是跨平臺的(特別是對於FreeBSD和Linux)。這個問題最好的解決方法是什麼?針對shell腳本的跨平臺getopt

+0

如果你開始使用的GNU getopt的長選項等,並打算讓你現有的代碼便攜和儘可能少的變化,那麼你可能會發現http://stackoverflow.com/a/37087374/324105有用。 – phils 2016-10-28 23:18:05

回答

14

使用getopts(帶有「s」)。

根據Bash FAQ 35

除非它的版本從UTIL-Linux操作系統,並使用其先進的模式,從來沒有使用getopt的(1)。 getopt不能處理空的參數字符串或嵌入空白的參數。請忘記它曾經存在過。

POSIX shell(和其他)提供getopts,它可以安全地使用。

+0

我使用Shell的助記符「S」,getopt「S」內置於BASH – 2012-12-19 05:53:12

+0

@ Dennis Williamson請更新您的答案:根據(更新後)FAQ條目:**除非是util-linux的版本,否則使用其高級模式,絕不使用getopt(1)。 ... ** – Florian 2015-10-16 11:10:50

+0

@Florian:更新。謝謝。 – 2015-10-16 17:55:26

0

getopt的基本語法是跨平臺的。

getopt vi: -v -i 100 file 
27

getopt命令基本上有兩個版本:原始版本和GNU增強版本。 GNU增強版本與原始版本向後兼容,所以如果您只使用原始版本的功能,它將與兩者兼容。

檢測哪些可用的getopt的版本

可以檢測哪個版本可用,並使用增強的功能,如果GNU增強版本,並限制自己原有的特色,如果GNU增強版本無法使用。增強版有一個-T選項用於測試哪個版本可用。

getopt -T > /dev/null 
if [ $? -eq 4 ]; then 
    # GNU enhanced getopt is available 
    set -- `getopt --long help,output:,version --options ho:v -- "[email protected]"` 
else 
    # Original getopt is available 
    set -- `getopt ho:v "[email protected]"` 
fi 

考慮使用內置的shell命令getopts(以「S」)來代替,因爲它更便於攜帶。但是,getopts不支持長選項(例如--help)。

如果您喜歡長選項,請使用getopt並使用上述測試來查看是否可以使用GNU增強版getopt。如果增強版本不可用,則腳本可以優雅地降級爲使用原始版本getopt(不支持長選項名稱和不支持空白)或使用getopts(不支持長選項名稱)。

使用GNU getopt的增強正確

獲取GNU增強版本與空白正確處理參數是棘手的。下面是它是如何做的:

ARGS=`getopt --long help,output:,verbose --options ho:v -- "[email protected]"` 
if [ $? -ne 0 ]; then 
    echo "Usage error (use -h for help)" >&2 
    exit 2 
fi 
eval set -- $ARGS 

# Parameters are now sorted: options appear first, followed by --, then arguments 
# e.g. entering: "foo bar" -o abc baz -v 
#  produces: -o 'abc' -v -- 'foo bar' 'baz' 

祕訣是使用"[email protected]"其中雙引號是非常重要的(在1號線),並eval設置命令(6號線)。

因此可以檢測並處理由getopt引發的錯誤,getopt的調用與eval分開進行,其中兩個由ARGS變量鏈接。

完整工作示例

PROG=`basename $0` 

getopt -T > /dev/null 
if [ $? -eq 4 ]; then 
    # GNU enhanced getopt is available 
    ARGS=`getopt --name "$PROG" --long help,output:,verbose --options ho:v -- "[email protected]"` 
else 
    # Original getopt is available (no long option names, no whitespace, no sorting) 
    ARGS=`getopt ho:v "[email protected]"` 
fi 
if [ $? -ne 0 ]; then 
    echo "$PROG: usage error (use -h for help)" >&2 
    exit 2 
fi 
eval set -- $ARGS 

while [ $# -gt 0 ]; do 
    case "$1" in 
     -h | --help)  HELP=yes;; 
     -o | --output) OUTFILE="$2"; shift;; 
     -v | --verbose) VERBOSE=yes;; 
     --)    shift; break;; # end of options 
    esac 
    shift 
done 

if [ $# -gt 0 ]; then 
    # Remaining parameters can be processed 
    for ARG in "[email protected]"; do 
    echo "$PROG: argument: $ARG" 
    done 
fi 

echo "$PROG: verbose: $VERBOSE" 
echo "$PROG: output: $OUTFILE" 
echo "$PROG: help: $HELP" 

這個例子可以從https://gist.github.com/hoylen/6607180

比較表上Wikipedia's entry on getopts比較了不同特徵下載。

+0

是的,'getopts'(帶s)是另一種選擇。可移植性純粹主義者仍然更喜歡getopt,因爲在1986年以前,古代Bourne炮彈中沒有getopts,但是這是一個不好的理由,因爲大多數/所有現代炮彈都支持得到選擇。更好的原因是如果可用,則可以輕鬆利用GNU增強的getup。 GNU增強的getopt允許操作數與選項混合並支持長選項名稱(這兩個功能都是getopts不支持的 - 參見[比較表] [1])。 – Hoylen 2014-06-17 03:19:20

+0

當我運行'eval set - $ ARGS'時,爲什麼會打印一個空的'--'?這是非常刺激。 – Hindol 2015-07-01 07:00:44