2017-02-22 83 views
0

擊功能如果我定義在bash殼的數組:與陣列輸入和輸出

a=() 
a+=("A") 
a+=("B") 
a+=("C") 

我可以與之交互的預期:

echo "${a[0]}" 
# Returns "A" 

echo "${a[1]}" 
# Returns "B" 

但是當我運行,通過相同的數組一個函數,我必須做一些錯誤的事情。首先,我將定義我的功能:

function sort_array { 
    declare -a array=("${!1}") 
    local sorted=() 

    sorted+=("1") 
    sorted+=("2") 
    sorted+=("3") 

    echo "${sorted[@]}" 
} 

現在,讓我們把它和檢查結果:

b=() 
b=$(sort_array a[@]) 
echo "${b[0]}" 

# Returns "1 2 3" 
# But I'm expecting b[0] == 1 

我在做什麼錯?我意識到我的例子可以完全刪除函數參數,但我的最終目標是編寫一個bash sort_array()函數,我可以傳遞一個數組並返回一個數組。

+0

什麼正在返回的是函數內部回聲,'的... B'它不是結果返回空。 –

+1

在函數調用之後加上'b =($ b)'給出預期的結果。 對數組變量的字符串賦值只會將該值放在第一個索引中。 – hbagdi

+0

@hbagdi做到了!我最終將賦值改爲了'b =($(sort_array a [@]))''。如果你想發佈這個答案,我會接受它。 –

回答

2

正如@chepner所說,bash沒有數組值。當你將一個數組傳遞給函數時,你真正在做的是將數組的每個元素作爲一個單獨的參數傳遞給該函數。

所有shell函數都可以return是一個單字節的退出代碼值0-255。他們唯一可以返回的東西就是輸出吧,用echo或者printf或者其他什麼;那麼調用者必須以常規方式捕獲輸出(命令替換,進程替換,重定向到要讀取的文件等)。

這就是說,如果你只是增加了一點語法來調用你原來的代碼將工作:

b=($(sort_array "${a[@]}")) 

但是,這依賴於解析爲個別單詞的有序數組是字符串的元素。一個更安全的版本將更改sort_array函數打印出每行一個元素;調用者然後可以使用內建的mapfile內容(別名readarray;需要Bash 4.x)將這些行讀入數組中。這看起來是這樣的:

function sort_array { 
    declare -a array=("[email protected]") 
    local sorted=() 

    sorted+=("1") 
    sorted+=("2") 
    sorted+=("3") 

    printf '%s\n' "${sorted[@]}" 
} 
mapfile -t b < <(sort_array "${a[@]}") 

,說在命令內<(...)輸出讀取陣列b; -t告訴它不要在數組值中包含換行符。

更安全的是使用空字符而不是換行符;最簡單的,如果你有這增加了一個選項,以mapfile的bash 4.4代替換行來使用不同的字符:

function sort_array { 
    declare -a array=("[email protected]") 
    local sorted=() 

    sorted+=("1") 
    sorted+=("2") 
    sorted+=("3") 

    printf '%s\0' "${sorted[@]}" 
} 
mapfile -t -d '\0' b < <(sort_array "${a[@]}") 
+2

請注意'mapfile'沒有不過,得到一個'-d'選項直到'bash' 4.4。 – chepner

+1

另外,在示例調用中,您仍將'$ 1'視爲'a [@]',但使用'「$ {a [0]}」''。 – chepner

+0

謝謝,@chepner。固定。 –

4

bash沒有數組的值。語句echo "${sorted[@]}"不會「返回」數組值,它只是將數組的每個元素寫入標準輸出,並由一個空格分隔。 (更具體地說,數組擴展產生一個單詞序列,每個元素一個,然後傳遞給echo作爲參數。)

bash中模擬有點困難。你必須創建一個全局數組參數,這是你在函數內部不能做的事情,直到bash 4.2。在bash中引入namerefs之前,使用該數組很困難。

sort_array() { 
    declare -n input=$1  # Local reference to input array 
    declare -ga "$2"  # Create the output array 
    declare -n output="$2" # Local reference to output array 

    # As a simple example, just reverse the array instead 
    # of sorting it. 
    n=${#input[@]} 
    for((i=n-1; i>=0; i--)); do 
     echo "*** ${input[i]}" 
     output+=("${input[i]}") 
    done 
} 

現在,您分別通過sort_array兩個參數,即輸入和輸出數組的名稱。

$ a=("foo 1" "bar 2" "baz 3") 
$ sort_array a b 
$ echo "${b[0]}" 
baz 3