帶有 for 迴圈和巢狀 if 語句的 Bash 函數給出了特殊的結果

帶有 for 迴圈和巢狀 if 語句的 Bash 函數給出了特殊的結果

我有以下 bash 函數,這讓我很困惑。如果我在 zenity 框中輸入以下內容...

員工 ID = 2 類別 ID = 3

我得到以下結果:2 3

如果...

員工 ID = 類別 ID = 3

第二個 zenity 視窗打開後,我輸入 2,得到以下結果: 2 3

然而當我進入

員工 ID = 2 類別 ID =

沒有打開其他 Zenity 窗口,我得到以下資訊:2

我真正想要的最終結果是測試運行後的 2,3 。

有人知道這裡出了什麼問題嗎?

#!/bin/bash


num(){
        emp=$(echo "$1" | awk -F, -v  OFS=, '{print $1 "," $2}')

        IFS=, read -ra array1 <<<"$emp"
        
        p=$(for i in "${array1[@]}"
        
        do
                
                if [[ "${i}" =~ ^[0-9]+$ ]]; then

                        out="${i}"
                elif
                        [[ "${i}" = NULL ]]; then

                        out="${i}"


                else   local var2

                        until [[ ${var2} =~ ^[0-9]+$ ]] || [[ ${var2} = NULL ]]; do

                                var2="$(zenity --forms --title="table salaries_wages" --text "Add a number"  --separator="," \
                                --add-entry="WARNING! You either forgot to enter or didn't enter a number. Please enter a valid number: ")"

                         done

                                out="${var2}"

        fi

        echo "$out"
        
done)
      
        echo "$p"
}

input="$(zenity --forms --title="table salaries_wages" --text="Add a new salaries_wages entry" --separator="," \
        --add-entry="ENTER employeeid: " \
        --add-entry="ENTER categoryid: ")"

num "$input"

答案1

這裡出了什麼問題?

您對工作方式的假設read與實際工作方式不同read。在 Bash 中運行此程式碼:

how_many () { IFS=, read -ra array1 <<<"$1"; echo "${#array1[@]}"; }
how_many "2,3"
how_many ",3"
how_many "2,"

你會得到221。最後一個數字很引人注目。這意味著尾隨分隔符號(,在本例中)read更像是終止符:後面的空字段不會讀入數組,並且數組最終會成為一個太短的元素。如果這種情況發生在您的程式碼中,for i in "${array1[@]}"則將僅針對第一個欄位執行循環。

解決辦法可能是引入一個額外的 ,故意作為尾隨終止符。那麼read永遠不會讀取第三個字段,但它總是會讀取兩個字段(即使第二個字段為空)。當我添加額外的內容時,看看有什麼不同,

how_many () { IFS=, read -ra array1 <<<"$1,"; echo "${#array1[@]}"; }
how_many "2,3"
how_many ",3"
how_many "2,"
how_many ","

2每次都是輸出。

要以這種方式修復程式碼,請使用<<<"$emp,"而不是<<<"$emp".


如果您修復程式碼,那麼當該else區塊運行多次時(即當兩個欄位最初都無效時),它將出現錯誤;因為你是重複使用var2變數再次。

我猜您曾經local var2避免這種情況,但local使變數在函數中本地化,而不是在else區塊中或在循環的單次迭代中for。您var2在該函數的相同實例中重複使用num

您呼叫該函數一次。它的內部var2總是相同的var2local只是使它與var2該函數的呼叫之外的任何外部不同。如果您var2在函數外部使用,則函數中的函數將是不同的。如果您調用num多次,則每次調用都將使用其自己的不同var2.這些都不會發生。您呼叫該函數一次並重複使用該變數那裡。當兩個字段無效時,變數將用於第一個字段,然後重複使用對於第二個欄位。

但是,如果您重建程式碼,則從validate循環內呼叫某些函數(例如):

for i in "${array1[@]}"; do validate "$i"; …

local var2並在函數中使用validate,那麼var2在函數的每次呼叫中都會是不同的。這就是如何local提供幫助。在每個循環中validate都將被重新調用,其局部變數將被重新初始化,而不與具有相同名稱的其他變數有任何連接。但是您仍然可以重複使用局部變數裡面該函數以破壞某些內容的方式(類似於您目前var2在該num函數中重複使用的方式)。

在我寫完上面的內容後,添加了一個範例已經連結的答案


注意p=$(stuff); echo "$p"幾乎等於echo "$(stuff)", 幾乎總是應該是 just stuff。請閱讀這個答案其中詳細闡述了var=$(stuff); echo "$var".

相關內容