Bash

在 while 循環中呼叫函式時,getopts 不獲取任何參數

  • September 18, 2020

我試圖在傳遞一些參數的while循環中呼叫一個函式。但是,getopts只能獲取第一次呼叫的參數。

這是一個最小的例子:

function add_all_external_services() {
 env | sed -n "s/^EXTERNAL_SERVICE_OPTIONS_\(.*\)$/\1/p" > options

 while read -r line
 do
   key="${line%%=*}"
   opt="${line#*=}"

   if [[ -n "$key" && -n "$opt" ]]; then
     echo "Adding external service \"$key\" with options: \"$opt\""
     add_external_service $opt
   else
     echo "Missing one or more variables:
 - Key: \"$key\"
 - Options: \"$opt\"
"
   fi
 done < options

 rm options
}

function add_external_service() {
 local local_service_name=""
 local external_service_name=""
 local external_service_namespace=""
 local service_url=""

 echo "    Options: $@"
 while getopts l:s:n:-: OPT; do
   if [[ "$OPT" = "-" ]]; then   # long option: reformulate OPT and OPTARG
     OPT="${OPTARG%%=*}"         # extract long option name
     OPTARG="${OPTARG#$OPT}"     # extract long option argument (may be empty)
     OPTARG="${OPTARG#=}"        # if long option argument, remove assigning `=`
   fi
   case "$OPT" in
     l | local-service-name)           needs_arg; local_service_name="$OPTARG" ;;
     s | external-service-name)        needs_arg; external_service_name="$OPTARG" ;;
     n | external-service-namespace)   needs_arg; external_service_namespace="$OPTARG" ;;
     external-name)                    needs_arg; service_url="$OPTARG" ;;
     ??* )                             die "Illegal option --$OPT" ;;  # bad long option
     \? )                              exit 2 ;;  # bad short option (error reported via getopts)
   esac
 done

 echo "      - local $local_service_name"
 echo "      - name $external_service_name"
 echo "      - namespace $external_service_namespace"
 echo "      - url $service_url"
}

然後,在呼叫時:

export EXTERNAL_SERVICE_OPTIONS_A="-l local_a -s rasa -n botinstance-12424526-review-feature-ce-swdjtf"
export EXTERNAL_SERVICE_OPTIONS_B="-l local_b -s review-feature-ce-swdjtf -n botinstance-12424526-review-feature-ce-swdjtf"

ventury-deploy add_all_external_services

我明白了:

Adding external service "B" with options: "-l local_b -s name_b -n namespace_b"
   Options: -l local_b -s name_b -n namespace_b
     - local local_b
     - name name_b
     - namespace namespace_b
     - url 
Adding external service "A" with options: "-l local_a -s name_a -n namespace_a"
   Options: -l local_a -s name_a -n namespace_a
     - local 
     - name 
     - namespace 
     - url 

我從這裡getopts得到了零件,每當我在循環外呼叫函式時它都可以正常工作。

在閱讀了這個問題之後,我嘗試&在循環內呼叫函式後添加 a ,它可以工作……所有的參數都是由getopts. 我不明白為什麼在後台執行命令會使其工作。

如果我echo $@在 之前getopts,我可以看到所有參數都正確傳遞,如果我手動呼叫第二個函式,每個 env 變數一次,它也可以正常工作。

那麼,在後台執行這些命令有什麼不同呢?我的意思是,有什麼不同getopts?另外,為什麼echo $@可以看到參數而getopts不能?

這是因為您沒有重置OPTIND. 根據手冊

每次呼叫時,getopts 將下一個選項放入 shell 變數名中,如果 name 不存在則初始化,並將下一個要處理的參數的索引放入變數 OPTIND 中。每次呼叫 shell 或 shell 腳本時,都會將 OPTIND 初始化為 1。

因此,OPTIND 用於跟踪要處理的下一個參數,並1在腳本啟動時自動設置為,但在函式結束時不會重置。

要修復您的腳本,只需添加OPTIND=1到函式的開頭:

function add_external_service() {
 OPTIND=1
 local local_service_name=""
 local external_service_name=""
 local external_service_namespace=""
 local service_url=""

 echo "    Options: $@"
 while getopts l:s:n:-: OPT; do
   if [[ "$OPT" = "-" ]]; then   # long option: reformulate OPT and OPTARG
     OPT="${OPTARG%%=*}"         # extract long option name
     OPTARG="${OPTARG#$OPT}"     # extract long option argument (may be empty)
     OPTARG="${OPTARG#=}"        # if long option argument, remove assigning `=`
   fi
   case "$OPT" in
     l | local-service-name)           needs_arg; local_service_name="$OPTARG" ;;
     s | external-service-name)        needs_arg; external_service_name="$OPTARG" ;;
     n | external-service-namespace)   needs_arg; external_service_namespace="$OPTARG" ;;
     external-name)                    needs_arg; service_url="$OPTARG" ;;
     ??* )                             die "Illegal option --$OPT" ;;  # bad long option
     \? )                              exit 2 ;;  # bad short option (error reported via getopts)
   esac
 done

 echo "      - local $local_service_name"
 echo "      - name $external_service_name"
 echo "      - namespace $external_service_namespace"
 echo "      - url $service_url"
}

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