可以使用 bash 數組代替 eval set –“$params”嗎?
我正在查看用於選項解析的optparse 庫,特別是生成程式碼中的這一位:
bash
params="" while [ $# -ne 0 ]; do param="$1" shift case "$param" in --my-long-flag) params="$params -m";; --another-flag) params="$params -a";; "-?"|--help) usage exit 0;; *) if [[ "$param" == --* ]]; then echo -e "Unrecognized long option: $param" usage exit 1 fi params="$params \"$param\"";; ##### THIS LINE esac done eval set -- "$params" ##### AND THIS LINE # then a typical while getopts loop
有什麼真正的理由在這裡使用
eval
嗎?輸入eval
似乎已正確清理。但是使用起來會不會一樣:params=() # ... --my-long-flag) params+=("-m");; --another-flag) params+=("-a");; # ... params+=("$param");; # ... set -- "${params[@]}"
這對我來說似乎更乾淨。
事實上,這是否允許通過使用而不是直接從
params
數組中解析選項(甚至不使用) ?set``while getopts "ma" option "${params[@]}"; do``while getopts "ma" option; do
您不需要在這裡使用
bash
數組(但如果感覺更好,請這樣做)。以下是如何做到這一點
/bin/sh
:#!/bin/sh for arg do shift case "$arg" in --my-long-flag) set -- "$@" -m ;; --another-flag) set -- "$@" -a ;; "-?"|--help) usage exit 0 ;; --*) printf 'Unrecognised long option: %s\n' "$arg" >$2 usage exit 1 ;; *) set -- "$@" "$arg" esac done
這比
bash
數組解決方案(個人意見)更乾淨,因為它不需要引入另一個變數。它也比您顯示的自動生成程式碼更好,因為它將每個命令行參數保留為"$@"
. 這很好,因為這允許使用者傳遞包含空格字元的參數,只要它們被引用(自動生成的程式碼不會這樣做)。風格評論:
- 上面的循環應該將長選項轉換為
getopts
稍後循環的短選項。因此,它通過實際執行某些選項(例如-?
和)而脫離了該任務--help
。恕我直言,這些應該被翻譯成-h
(或一些合適的短選項)。- 它還翻譯過長的選項,超過了不應接受選項的點。呼叫腳本為
./script.sh --my-long-flag -- -?
-?
由於--
(意思是“選項到此結束”),不應解釋為選項。同樣地,./script.sh filename --my-long-flag
不應解釋
--my-long-option
為選項,因為選項的解析應在第一個非選項處停止。這是一個考慮到上述情況的變體:
#!/bin/sh parse=YES for arg do shift if [ "$parse" = YES ]; then case "$arg" in --my-long-flag) set -- "$@" -m ;; --another-flag) set -- "$@" -a ;; --help) set -- "$@" -h ;; --) parse=NO set -- "$@" -- ;; --*) printf 'Unrecognised long option: %s\n' "$arg" >$2 usage exit 1 ;; *) parse=NO set -- "$@" "$arg" esac else set -- "$@" "$arg" fi done
這不允許的是帶有**單獨選項參數的長選項,例如
--option hello
(hello
將被視為非選項並且選項解析將結束)。不過,通過一些額外的修補,類似的事情--option=hello
會很容易處理。
問題是“是否應該使用 bash 數組代替 eval set — “$params”?”,答案是肯定的!.
在您的腳本中, eval 的輸入顯然沒有得到適當的清理。嘗試
yourscript '`xterm`'
即使反引號被單引號正確引用,您也會看到 xterm 已啟動。(與之比較
echo '`xterm`'
它不會啟動 xterm。)
在保留的同時修復錯誤
eval
非常困難。甚至換線params="$params \"$param\"";;
到
params="$params '$param'";;
無濟於事:現在
yourscript '`xterm`'
不再啟動 xterm,但
yourscript \'' `xterm` '\'
仍然如此。