Bash

可以使用 bash 數組代替 eval set –“$params”嗎?

  • December 20, 2018

我正在查看用於選項解析的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 hellohello將被視為非選項並且選項解析將結束)。不過,通過一些額外的修補,類似的事情--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` '\'

仍然如此。

引用自:https://unix.stackexchange.com/questions/253481