Bash

將 $@ 分配給 shell 函式中的另一個變數

  • March 26, 2020

我正在製作一個gc可以區分 git commit/checkout 的智能別名。

如果gc在沒有任何參數或使用-a,-m參數的情況下呼叫,則執行 git commit。否則,執行 git checkout (如果有一個b帶有附加參數的標誌)。如果呼叫 gc 的任何其他變體,我寧願它拋出錯誤而不是做一些意想不到的事情。

到目前為止,這是我的 shell 函式。

gc() {
   args=$@
   commit=false
   checkout=false

   # Check flags
   while getopts ":am:b" opt; do
       case $opt in
           a|m)
               commit=true
               ;;
           b)
               checkout=true
               ;;
           \?)
               echo "Unknown flags passed."
               return 1
               ;;
       esac
   done

   shift "$((OPTIND-1))"

   # Check number of arguments
   if [[ "$#" == 0 ]]; then
       commit=true
   elif [[ "$#" == 1 ]]; then
       checkout=true
   else
       echo "Too many arguments"
       return 1
   fi

   # Finally run respective command
   if [[ $commit == true && $checkout == true ]]; then
       echo "Unable to ascertain which operation you would like to perform."
       return 1
   elif [[ $commit == true ]]; then
       git commit "$args"
   elif [[ $checkout == true ]]; then
       git checkout "$args"
   else
       echo "Undefined behavior"
       return 1
   fi
}

但是,這不能正常工作。經過一番試驗,我發現分配$@給另一個變數是根本原因,但我無法理解為什麼以及到底出了什麼問題。

另外,由於我是第一次編寫 shell 函式,因此請突出顯示我所犯的任何錯誤。

$@是一個數組,將其分配給一個數組:

args=("$@")

然後將其用作數組:

elif [[ $commit == true ]]; then
   git commit "${args[@]}"
elif [[ $checkout == true ]]; then
   git checkout "${args[@]}"
else

目前程式碼中發生的情況是,所有單獨的參數都儲存為單個字元串。所以如果你打電話:

bc -a "foo bar"

這被分配args為:

args='-a foo bar'

然後代替執行:

git commit -a "foo bar"

你得到:

git commit '-a foo bar'

由於另一個答案不是 POSIX,所以這裡有一個替代方案。如果你想暫時粉碎位置參數,你可以這樣做:

s1=$(printf '%s\n' "$@")

然後當您準備好恢復時,請執行以下操作:

IFS='
'
set -- $s1

請注意,這假定參數不包含換行符。如果是這樣,則需要使用不同的分隔符。

旁注:如果您注意到,最後一行包含一個未引用的變數。這是可以接受不帶引號的變數的少數情況之一(在我看來,這是唯一的情況):使用者已明確設置IFS. 使用者基本上說“是的,我知道我在做什麼,請繼續”。

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