Bashには2種類のパラメータがあります。「スカラー」値と配列です。 スカラー値は文字列か数値で、1つの「もの」を表します。
ほとんどの場合、スカラー値でデータを扱うのに十分です。 でもときには、スカラー値のリストを保存する必要があります。 そんなときは_配列_を使います。
配列には2種類あります。
このドキュメントの最初のいくつかのセクションでは、数値インデックスの配列(以降、単に「配列」と呼びます)を扱います。 連想配列の詳細は最後に登場します。
Bashの配列はスカラー値_しか_保存できません。 2次元配列(配列の配列)を作ることはできません。
括弧(())で囲んだ要素のリスト(空でもかまいません)を変数に代入することで、配列を初期化できます。
myarray=("one" "two" "three")
すべての変数代入と同じく、イコールの前後にスペースを入れてはいけません。
要素の間にカンマの区切りはありません。空白で区切られた文字列のリストであることに注意してください。
実際、括弧の中の空白の量はまったく自由です。 改行も使えます。読みやすくするために、好きなだけ使ってかまいません。
myarray=(
"first element"
"second element"
"this is the last element"
)
この方法で文字列のリストを配列変数に代入すると、最初の文字列はインデックス0に、次の文字列はインデックス1に、その次はインデックス2に、というように保存されます。
必要なインデックスを指定することで、「スパース配列」を初期化することもできます。
raindrops=([3]="Pling" [5]="Plang" [7]="Plong")
繰り返しますが、配列のインデックスは0から始まります。 このコードは"true"を出力します:
myarray=("one" "two" "three")
[[ "${myarray[0]}" == "one" ]] && echo true || echo false
declare(関数の中ではlocal)コマンドを使って、変数が配列を保持することを指定できます。
declare -a myarray
より自然なのは、(空かもしれない)括弧で囲んだリストを代入して変数を初期化する方法です。
上のノートで見たように、配列の要素にアクセスする構文は${myarray[$index]}です。
インデックスは角括弧([])で指定します。
波括弧({})は必須です。
数値インデックスの配列では、インデックスは算術式です。 Bashのマニュアルには次のように書かれています:
算術式の中では、シェル変数はパラメータ展開の構文を使わずに、名前で参照することもできます。
つまり「単純な」変数展開では$は必要ありません。
次のように要素にアクセスできます。こちらのほうが少し読みやすいでしょう:
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[@]}"を使います。
数値インデックスの配列では、インデックスは数値の順に展開されます。
値だけでなくインデックスも必要な場合があります。 これにはいくつかの方法があります。
インデックスが途切れない連続した並びになっているとわかっている場合は、算術forループを使えます。
for ((i = 0; i < ${#myarray[@]}; i++)); do
echo "$i -> ${myarray[i]}"
done
配列名の前に#文字を付けた${#myarray[@]}という構文に注目してください。
配列のインデックスは0から始まるので、配列の最後のインデックスは配列の長さより1小さくなります。
配列がスパースな場合は、次の形式を使えます:
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
これは、シェルの標準的なクォート形式で中身を出力します。
declare -a a=([0]="the 'first' element" [1]="second" [2]="third" [3]="the \"last\" element")
繰り返しますが、連想配列はインデックスに数値ではなく文字列を使います。 ここまでに書いたことはすべて連想配列にも当てはまりますが、小さな違いがあります。 一般的には「インデックス」ではなく「キー」という用語を使います。連想配列はキーを値に対応付けます。
配列とは違い、連想配列は必ず宣言する必要があります。
declare(関数の中ではlocal)に-Aオプションを付けます:
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")
連想配列には順序がないことに注意してください。
宣言と初期化は1行で行えます。
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
もう一度強調すると、キーに順序はありません。