2011-10-05 79 views
9

我使用getopt(不getops)爲我的bash腳本來處理選項和開關(包括長--option和短-o形式)的能力。捕獲getopt的無效選項

我希望能夠捕獲無效的選項和處理它們,通常呼應的是,用戶應該儘量cmd --help,然後退出腳本。

的是,無效的選項都陷入由getopt的,這本身就是輸出信息,如「getopt的:無效選項 - ‘X’」

下面是我使用的設置我的getopt的格局參數:

set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]") 

其中$ LONG_OPTIONS和$ SHORT_OPTIONS都是以逗號分隔的選項列表。

這裏是我如何處理加工的選項:

while [ $# -gt 0 ] 
    do 
     case "$1" in 
      -h|--help) 
       cat <<END_HELP_OUTPUT 

    Help 
    ---- 

    Usage: ./cmd.sh 

    END_HELP_OUTPUT 

       shift; 
       exit 
       ;; 
      --opt1) 
       FLAG1=true 
       shift 
       ;; 
      --opt2) 
       FLAG2=true 
       shift 
       ;; 
      --) 
       shift 
       break 
       ;; 
      *) 
       echo "Option $1 is not a valid option." 
       echo "Try './cmd.sh --help for more information." 
       shift 
       exit 
       ;; 
     esac 
    done 

getopt -q將抑制產量,但case語句中我捕獲方案仍不能做我的期望。相反,程序只是執行,儘管無效的參數。

回答

8

This那種風格的作品對我來說:

params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "[email protected]")" 

if [ $? -ne 0 ] 
then 
    usage 
fi 

eval set -- "$params" 
unset params 

while true 
do 
    case $1 in 
     -d|--diff) 
      diff_exec=(${2-}) 
      shift 2 
      ;; 
     -h|--help) 
      usage 
      exit 
      ;; 
     --) 
      shift 
      break 
      ;; 
     *) 
      usage 
      ;; 
    esac 
done 
+0

達到哪種情況*)? – jarno

+0

@jarno如果你的'case'語句和'getopt'調用之間有不匹配的地方,它會被捕獲。這只是防守編程。 – l0b0

0

我不知道這是否可以幫助,但getopt的(1)使用的getopt(3),如果我沒有記錯的getopt (3)抑制錯誤報告,如果OPTSTRING的拳頭人物是冒號。

+0

使用 ':' 作爲optstring內的第一個字符抑制消息輸出。但是,getopt(1)的返回碼仍然不爲零,而無法識別的選項不會通過getopt(1)獲得輸出。 –

1

這還不是最強大的解決方案,但它是合理的;它依賴於以下:

  • 該錯誤消息getopt打印帶有前綴「getopt的:」
  • 的假設是,這是可以接受通過getopt的錯誤消息的清理後的版本,增強與自定義信息。

代碼片段:

# Invoke getopt; suppress its stderr initially. 
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]" 2>/dev/null) 
if [[ $? -ne 0 ]]; then # getopt reported failure 
    # Rerun the same getopt command so we can capture stderr output *only* this time. 
    # Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input. 
    # Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here. 
    errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]" 2>&1 1>&-) 
    # Strip getopt's prefix and augment with custom information. 
    echo -e "${errmsg#getopt: }\nTry './cmd.sh --help for more information." 1>&2 
    exit 1 
fi 
+0

可以工作,呃?就像你說的,很脆弱。 –

+0

@TomAuger:如果您認爲「非常脆弱」充分闡釋「不是最健壯但合理」,您必須運行不兼容的英文版外殼。總是試圖從'getopt'中可靠地獲取信息,它不是以編程方式報告的,這將會非常棘手。也就是說,關於假設stderr輸出爲先的部分實際上是不穩定的,所以我修改了代碼來解決這個問題。如果您如何從單個命令執行中捕獲stdout和stderr爲單獨的變量(不涉及顯式創建臨時文件),請告訴我。 – mklement0

1

你必須使用getopt的呢?如果只是用

while [ $# -gt 0 ]; do 
    case "$1" in 
    -d|--diff) 
     diff_exec=(${2-}) 
     shift 
     ;; 
    -h|--help) 
     usage 
     exit 
     ;; 
    --) 
     break 
     ;; 
    *) 
     usage 
     ;; 
    esac 
    shift 
done 

然後你自己的代碼做了檢查。

1

我發現這作爲getopts的case語句中的最後一項工作:

*)EVAL回聲 「無法識別的ARG \ $$ [OPTIND-1]」;用法;出口 ;;

0

這裏是一個命令行解析我已經使用。它可以通過更多的解析邏輯來處理丟失的選項和參數。

對於命令行:-a AA BB -b -c CC,結果S/BA = AA B = BB C = CC

OPT=("[email protected]") # Parses the command line into words. 

for [[ I=0;I<${#OPT[@]};I++ ]] 
    do 
     case "${OPT[$I]}" in   
     -a) a=${OPT[$I+1]} ;;   
     -b) b=${OPT[$I+1]} ;;   
     -c) c=${OPT[$I+1]} ;;  
     esac 
    done