2013-07-25 77 views
1

我創建了一個涉及解析參數的bash腳本。用法是:使用值列表解析標誌

$ ./my_script.sh -a ARG_1 -b ARG_2 [-c LIST_OF_ARGS...] 

使用getopts我能夠解析-a-b並獲得各自的價值ARG_1ARG_2。當且僅當用戶將-c作爲最後一個參數時,我也可以得到-c並創建一個列表,其中包含所有LIST_OF_ARGS...中的值。

但我不想強制用戶插入-c作爲最後一個標誌。舉例來說,那將是巨大的,如果該腳本可以通過這種方式調用:

$ ./my_script.sh -b ARG_2 -c V1 V2 V3 -a ARG_1 

這裏是我當前的代碼:

while getopts a:b:c opt 
do 
    case $opt in 
     a) 
      A_FLAG=$OPTARG 
      ;; 
     b) 
      B_FLAG=$OPTARG 
      ;; 
     c) 
      # Handle values as regular expressions 
      args=("[email protected]") 
      C_LIST=() 
      for ((i=$OPTIND-1 ; i <= $#-1 ; i++)) 
      do 
       C_LIST=("${C_LIST[@]}" ${args[$i]}) 
      done 
      ;; 
     ?) 
      usage 
      ;; 
    esac 
done 
+1

'getopts'不支持多參數選項。你基本上需要手動解析參數,計算遵循'-c'作爲參數傳遞給該選項的參數,直到你到達另一個定義選項或列表的末尾。 – chepner

+1

在現有的代碼,你會過得更好寫一個簡單的表達式:'C)C_LIST =( 「$ OPTARG」 「$ {@:$ OPTIND}」);;'這將正確處理'的情況下-cV1 V2 V3 '而且它也縮短了很多。 (另外,學會在數組上使用'+ =')。但是這並不能回答你的問題。 – rici

回答

1

在我的系統,我還沒有一個/usr/share/doc/util-linux/examples/getopt-parse.bash文件。它將getopt的結果放入一個變量中,並將位置參數設置爲該變量。然後使用類似於您的switch,但使用shift在找到時刪除參數。

你可以做類似的事情,但對於你的-c選項使用shift,直到你得到一個選項或用完參數。


或者它可能是足夠你使用當前的解決方案,但記得要設置OPTIND變量在循環之後。

1

您需要將檢測到的-c標誌與與其關聯的處理分開。例如,像:

while getopts a:b:c opt 
do 
    case $opt in 
     a) 
      A_FLAG=$OPTARG 
      ;; 
     b) 
      B_FLAG=$OPTARG 
      ;; 
     c) 
      C_FLAG=1 
      ;; 
     ?) 
      usage 
      ;; 
    esac 
done 

# discard all of our options. 
shift `expr $OPTIND - 1` 

if [ "$C_FLAG" = 1 ]; then 
      # Handle values as regular expressions 
      args=("[email protected]") 
      C_LIST=() 
      for ((i=0 ; i <= $#-1 ; i++)) 
      do 
       C_LIST=("${C_LIST[@]}" ${args[$i]}) 
      done 
fi 

這個腳本不能收集所有非選項參數,直到處理所有的命令行選項之後。

+0

您的解決方案不起作用,因爲它不處理輸入「-a ARG_1 -c LIST_OF_ARGS ... -b ARG_2」。讀取參數後,for循環獲取'-c LIST_OF_ARGS ... -b ARG_2',但在那一點上,我希望-b可能已經被解析。 –

+0

從你的問題中不清楚你是否期望特定的置換工作。 – larsks

1

下面是一個問題:爲什麼有一個-c選項?

如果完整的用法涉及到值列表,爲什麼不只是沒有-c選項,只允許-a和-b選項,其餘的是常規參數,如./myscript.sh -a ARG_1 -b ARG_2 [argument ...],其中任何參數都是可選的(如-c選項及其參數在您使用示例

然後你的問題是「我怎麼點綴程序選項和參數」,而我會迴應:「你不應該這樣做,但無論如何要實現這一目標,你自己解析命令行; getopts將不會按照你想要的方式工作。「

當然,解析是困難的方法。另一種可能性是在-c之後添加值到一個列表,只要你沒有遇到另一種選擇或選項的結束:

C_LIST=() 
while getopts a:b:c: opt; do 
    #Skipping code... 
    c) 
     C_LIST+="$OPTARG" 
     shift $(expr $OPTIND - 1) 
     while [ -n "$1" ] && [ $(printf "%s" "$1" | grep -- '^[^-]') ]; do 
      C_LIST+="$1" 
      shift 
     done 
     OPTIND=1 
     ;; 

getopts的的行爲模仿:即使OPTARG以「 - 」字符,它仍然保持,但是在OPTARG之後,任何以' - '開始的字符串可能只是一個無效的選項,例如-n。我使用printf而不是echo,因爲某些版本的echo(例如bash內置的版本)有一個-e選項,可能允許或不允許循環繼續,這是不希望的。 grep表達式應該可以防止這種情況發生,但是誰知道該版本的echo是否允許-e'hello',這會導致grep成功,因爲它會看到「hello」?儘管可能不必要,但爲什麼要冒險?

就個人而言,我想如果你能避免這種行爲,但我也想不明白你爲什麼要問這個問題擺在首位。如果我要推薦任何東西,我會建議比任何其他可能的實現選擇更爲常見的風格/path/to/script -a ARG_1 -b ARG_2 [argument ...]

+0

@Joachim Pileborg當然'/ path/to/script -a ARG_1 -b ARG_2 [argument ...]'符合我的需求。但是,在一個通用的方法,它不適合使用'/路徑/到/腳本-a ARG_1 -b ARG_2 [-c列表...] [-d ANOTHER_LIST ...]。顯然@ larsks的解決方案將起作用 –