陣列

陣列 在 Bash

{other: "%{count} 個練習"}

關於 陣列

Bash 提供兩種參數型別:純量值和陣列。 純量值可以是字串或數字,代表單一的「東西」。

大多數情況下,純量值就足以存放你的資料。 但有時候,你需要儲存一連串的純量值。 這時你就會用到_陣列_。

陣列有兩種:

  • 以數字索引的陣列會把整數鍵對應到字串值。 (其他程式語言可能稱之為「串列」或「序列」。)
  • 關聯式陣列會把字串鍵對應到字串值。 (其他程式語言可能稱之為「映射」或「字典」。)

本文件開頭幾節會介紹以數字索引的陣列(以下簡稱「陣列」)。 關於關聯式陣列的細節會出現在最後面。

Caution

Bash 陣列_只能_儲存純量值。 沒有辦法建立二維陣列(陣列的陣列)。

宣告與初始化陣列變數

你可以把一串用括號括起來的元素清單(可以是空的)指定給變數,藉此初始化陣列。

myarray=("one" "two" "three")

如同所有的變數賦值,等號兩邊不能有空格。

請注意,元素之間沒有逗號分隔;這是一份以空白分隔的字串清單。

事實上,括號內要放多少空白完全隨意。 也可以換行;想用幾行就用幾行,讓程式更好讀。

myarray=(
    "first element"
    "second element"
    "this is the last element"
)

用這種方式把字串清單指定給陣列變數,會把第一個字串存在索引 0,下一個存在索引 1,再下一個存在索引 2,以此類推。

你也可以明確指定需要的索引,來初始化「稀疏陣列」。

raindrops=([3]="Pling" [5]="Plang" [7]="Plong")
Note

再強調一次:陣列索引是從零開始的。 這段程式碼會輸出 "true":

myarray=("one" "two" "three")
[[ "${myarray[0]}" == "one" ]] && echo true || echo false

你可以使用declare指令(在函式內則是local)來指定某個變數會存放陣列。

declare -a myarray

更道地的做法是直接指定一串(可能是空的)括號清單來初始化變數。

存取陣列的元素

如上面的注意事項所述,存取陣列元素的語法是${myarray[$index]}。 索引寫在方括號裡。 大括號是必要的。

Note

對以數字索引的陣列來說,索引是一個算術運算式。 Bash 手冊指出:

在算術運算式中,也可以直接用名稱參照 shell 變數,而不使用參數展開語法。

這表示「簡單的」變數展開並不需要$。 你可以像這樣存取元素,讀起來比較容易:

i=5
echo "${myarray[i]}"
# ..............^

如果指定的索引不存在於陣列中,展開的結果會是空字串。

對陣列賦值

要指定某個特定的陣列項目,請使用這個語法:

myarray[10]="hello"

要_附加_到陣列,請使用+=這個串接賦值運算子,並加上括號:

myarray+=("new element 1" "new element 2")

疊代陣列

你通常會需要疊代陣列的_值_。 使用for迴圈(你在迴圈概念中看過):

myarray=("one" "two" "three")
for value in "${myarray[@]}"; do
    echo "$value"
done

請注意展開陣列的特殊語法:"${myarray[@]}" 這種參數展開形式會把陣列的值替換成各自獨立的詞。 這大致等同於:

for value in "${myarray[0]}" "${myarray[1]}" ... "${myarray[n]}"

"${myarray[@]}"這種形式也能用在稀疏陣列上,只會展開已定義的值。

這種特殊展開(索引是@符號)只有在雙引號內才具有特殊意義。

其他特殊的參數展開

這裡還有幾個疊代陣列時會用到的特殊語法。 手冊在參數展開一節中有說明。

要找出陣列的_長度_,請使用${#myarray[@]},在名稱前面加上#。 陣列的「長度」指的是其中元素的數量。

要取出陣列的_索引_清單,請使用"${!myarray[@]}",在名稱前面加上!,並把展開式放在雙引號內。 對以數字索引的陣列來說,索引會依數字順序展開。

疊代陣列索引

有時候你除了值之外,也需要索引。 有幾種做法。

  1. 當你知道索引是連續不中斷的,可以使用_算術_for迴圈。

    for ((i = 0; i < ${#myarray[@]}; i++)); do
        echo "$i -> ${myarray[i]}"
    done
    

    請注意${#myarray[@]}這個語法,#字元放在陣列名稱前面。 由於陣列使用從零開始的索引,陣列的最後一個索引會比陣列長度少一。

  2. 當陣列是稀疏的,可以使用這種形式:

    for index in "${!raindrops[@]}"; do
        echo "$index -> ${raindrops[index]}"
    done
    

    請注意${!myarray[@]}這個語法,!字元放在陣列名稱前面。

檢視陣列

如果你想看看陣列的內容,請使用帶有-p選項的declare指令:

a=("the 'first' element"
   second
   third
   'the "last" element')
declare -p a

這會以 shell 的標準引號格式輸出內容。

declare -a a=([0]="the 'first' element" [1]="second" [2]="third" [3]="the \"last\" element")

關聯式陣列

再次強調,關聯式陣列使用字串作為索引,而不是數字。 上面寫的一切都適用於關聯式陣列,只是有些小差異。 一般來說,我們會說「鍵」而不是「索引」:關聯式陣列把鍵對應到值。

宣告關聯式陣列

和陣列不同,關聯式陣列必須先宣告。 請使用declare的-A選項(在函式內則是local):

declare -A mymap

myfunc() {
    local -A my_local_map
    # ...
}

初始化關聯式陣列

鍵值對寫在括號清單裡:

mymap=([first]=foo [second]=bar [third]=baz)
declare -p mymap

輸出結果為:

declare -A mymap=([second]="bar" [first]="foo" [third]="baz")
Note

請注意,關聯式陣列是無序的。

宣告和初始化可以寫在同一行。

declare -A mymap=([first]=foo [second]=bar [third]=baz)

在較新的 Bash 版本中,初始化可以使用(key value key value ...)這種清單。

declare -A mymap=(first foo second bar third baz)

存取值

存取元素使用和之前相同的語法:${mymap[$key]}。

關聯式陣列的鍵不會在算術情境中求值。 必須使用一般的參數展開語法。

對關聯式陣列賦值

賦值使用和之前相同的語法:

mymap[$key]="$value"

疊代

你可以用for value in "${mymap[@]}"迴圈來疊代。 不過,你通常也會想要連同值一起取得鍵。

請使用我們上面看過的"${!mymap[@]}"語法。

for key in "${!mymap[@]}"; do
    echo "$key -> ${mymap[$key]}"
done

輸出結果為

second -> bar
first -> foo
third -> baz

再次強調,鍵沒有順序。

透過 GitHub 編輯 連結會在新視窗或分頁中開啟