Bash:為什麼在解析命令行參數的腳本中使用 eval 和 shift?
當我在尋找這個答案https://stackoverflow.com/a/11065196/4706711時,為了弄清楚如何使用參數,
--something
或者-s
關於答案腳本的一些問題:#!/bin/bash TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \ -n 'example.bash' -- "$@"` if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi # Note the quotes around `$TEMP': they are essential! eval set -- "$TEMP" while true ; do case "$1" in -a|--a-long) echo "Option a" ; shift ;; -b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;; -c|--c-long) # c has an optional argument. As we are in quoted mode, # an empty parameter will be generated if its optional # argument is not found. case "$2" in "") echo "Option c, no argument"; shift 2 ;; *) echo "Option c, argument \`$2'" ; shift 2 ;; esac ;; --) shift ; break ;; *) echo "Internal error!" ; exit 1 ;; esac done echo "Remaining arguments:" for arg do echo '--> '"\`$arg'" ; done
首先,該
shift
程序在以下行中做了什麼:-a|--a-long) echo "Option a" ; shift ;;
eval
之後在以下行中使用命令的目的是什麼:eval set -- "$TEMP"
我試圖在上面提到的腳本中評論這一行,我得到了以下回复:
$ ./getOptExample2.sh -a 10 -b 20 --a-long 40 -charem --c-long=echi Param: -a Option a Param: 10 Internal error!
但是,如果我取消註釋,它就會像魅力一樣執行:
Option a Option b, argument `20' Option a Option c, argument `harem' Option c, argument `echi' Remaining arguments: --> `10' --> `40'
解析選項時要做的許多事情之一
getopt
是重新排列參數,以便非選項參數排在最後,並且組合的空頭選項被拆分。來自man getopt
:Output is generated for each element described in the previous section. Output is done in the same order as the elements are specified in the input, except for non-option parameters. Output can be done in compatible (unquoted) mode, or in such way that whitespace and other special characters within arguments and non-option parameters are preserved (see QUOTING). When the output is processed in the shell script, it will seem to be composed of distinct elements that can be processed one by one (by using the shift command in most shell languages). [...] Normally, no non-option parameters output is generated until all options and their arguments have been generated. Then '--' is generated as a single parameter, and after it the non-option parameters in the order they were found, each as a separate parameter.
這種效果反映在您的程式碼中,其中選項處理循環假定所有選項參數(包括選項的參數)首先出現,然後分別出現,最後是非選項參數。
因此,
TEMP
包含重新排列、引用、拆分的選項,並使用eval set
使它們成為腳本參數。為什麼
eval
?您需要一種安全地將輸出轉換getopt
為參數的方法。這意味著安全地處理特殊字元,如空格、、'
("
引號)、*
等。為此,將getopt
它們轉義到輸出中以供 shell 解釋。沒有eval
,唯一的選擇是set $TEMP
,但是您僅限於通過欄位拆分和通配而不是 shell 的完整解析能力來實現的功能。假設你有兩個論點。沒有辦法在不額外限制參數中可用的字元的情況下僅使用欄位拆分將這兩個作為單獨的單詞(例如,假設您將 IFS 設置為
:
,那麼您不能:
在參數中使用)。因此,您需要能夠轉義這些字元並讓 shell 解釋轉義,這就是eval
需要的原因。除非出現重大錯誤getopt
,否則它應該是安全的。至於
shift
,它會做它一直做的事情:刪除第一個參數,並移動所有參數(因此$2
現在將是$1
)。這消除了已處理的參數,因此,在此循環之後,只剩下非選項參數,您可以方便地使用$@
而不必擔心選項。