配列
| 対応: | Bash(bash拡張) |
|---|
『シェルスクリプト』では bash を使うと通常の配列(インデックス配列)と連想配列(キーと値のペア)を扱えます。ファイル一覧やコマンド引数など複数の値をまとめて処理したいときに配列が役立ちます。連想配列は declare -A で宣言が必要な bash 4.0 以降の機能です。
通常配列(インデックス配列)の宣言と代入
通常配列は () を使って一括で宣言するか、インデックスを指定して1つずつ代入します。インデックスは 0 から始まります。
| 書き方 | 説明 |
|---|---|
arr=(a b c) | スペース区切りで要素を並べて配列を一括宣言します。インデックスは 0 から自動で割り当てられます。 |
arr[0]=a | インデックス 0 に値 a を代入します。任意のインデックスを個別に指定して代入できます。 |
arr+=( d e ) | 既存の配列の末尾に要素を追加します。 |
declare -a arr | 変数を明示的にインデックス配列として宣言します。代入と同時に書いても問題ありません。 |
通常配列の参照・操作
配列の要素を参照するときは ${arr[n]} と書きます。全要素を展開するには ${arr[@]} を使います。
| 書き方 | 説明 |
|---|---|
${arr[0]} | インデックス 0 の要素を取得します。 |
${arr[@]} | 全要素を個別の文字列として展開します。for ループや引数渡しに使います。ダブルクォートで囲むと要素内のスペースを保持できます。 |
${arr[*]} | 全要素を IFS の最初の文字(デフォルトはスペース)で結合した1つの文字列として展開します。 |
${#arr[@]} | 配列の要素数(長さ)を返します。 |
${!arr[@]} | 配列の全インデックス(添字)を返します。インデックスが連続していない場合に有効です。 |
unset arr[n] | インデックス n の要素を削除します。他の要素のインデックスは詰められません。 |
unset arr | 配列全体を削除します。 |
${arr[@]:s:n} | インデックス s から n 個の要素を取り出します(スライス)。 |
連想配列(declare -A)
連想配列を使うには必ず declare -A で事前に宣言します。キーは文字列で、数値インデックスの代わりに意味のある名前を使えます。bash 4.0 以降が必要です。
| 書き方 | 説明 |
|---|---|
declare -A map | 変数 map を連想配列として宣言します。宣言前に代入しても通常変数になってしまうため、必ず先に宣言します。 |
map[key]=value | キー key に値 value を代入します。 |
declare -A map=([k1]=v1 [k2]=v2) | 宣言と同時にキーと値を一括で設定します。 |
${map[key]} | キー key の値を取得します。 |
${map[@]} | 全値を展開します。順序は保証されません。 |
${!map[@]} | 全キーを展開します。 |
${#map[@]} | 連想配列の要素数を返します。 |
unset map[key] | キー key の要素を削除します。 |
ループでの展開
配列の全要素を処理するには for ... in "${arr[@]}" を使います。連想配列をキーと値のペアで処理するには ${!map[@]} でキーを取り出し、${map[$key]} で値を参照します。
| パターン | 説明 |
|---|---|
for item in "${arr[@]}"; do ... done | 通常配列の全要素を1つずつ取り出してループします。ダブルクォートで囲まないとスペースを含む要素が分割されてしまいます。 |
for i in "${!arr[@]}"; do ... done | インデックスを取り出してループします。${arr[$i]} で値を参照できます。 |
for key in "${!map[@]}"; do ... done | 連想配列の全キーを取り出してループします。${map[$key]} で対応する値を参照できます。 |
サンプルコード
dragonball_array.sh
#!/bin/bash
# -----------------------------------------------
# ドラゴンボールのキャラクターで通常配列の
# 宣言・操作・ループを確認します
# -----------------------------------------------
# -----------------------------------------------
# 1. 配列の宣言(一括)
# -----------------------------------------------
# () でスペース区切りに並べると 0 から順にインデックスが振られます
fighters=("悟空" "ベジータ" "ピッコロ" "クリリン" "トランクス")
echo "=== 通常配列 fighters ==="
# 特定のインデックスを参照します
echo "fighters[0]: ${fighters[0]}" # 悟空
echo "fighters[2]: ${fighters[2]}" # ピッコロ
echo ""
# -----------------------------------------------
# 2. 全要素の展開と要素数
# -----------------------------------------------
# ${fighters[@]} で全要素を展開します
echo "全キャラクター: ${fighters[@]}"
# ${#fighters[@]} で要素数を取得します
echo "キャラクター数: ${#fighters[@]} 人" # 5 人
echo ""
# -----------------------------------------------
# 3. for ループで全要素を処理します
# -----------------------------------------------
echo "=== 参戦キャラクター ==="
for name in "${fighters[@]}"; do
echo " - ${name}"
done
echo ""
# -----------------------------------------------
# 4. インデックス付きループ
# -----------------------------------------------
echo "=== インデックス付き一覧 ==="
for i in "${!fighters[@]}"; do
echo " [${i}] ${fighters[$i]}"
done
echo ""
# -----------------------------------------------
# 5. 要素の追加・削除
# -----------------------------------------------
# += で末尾に要素を追加します
fighters+=("悟飯")
echo "追加後の要素数: ${#fighters[@]} 人"
# unset で特定のインデックスを削除します(インデックスは詰められません)
unset fighters[1] # ベジータを削除します
echo "削除後の全要素: ${fighters[@]}"
# ${!fighters[@]} で残っているインデックスを確認します
echo "残りのインデックス: ${!fighters[@]}"
echo ""
# -----------------------------------------------
# 6. スライス
# -----------------------------------------------
# インデックス 2 から 2 要素を取り出します
echo "スライス [2:2]: ${fighters[@]:2:2}"
chmod +x dragonball_array.sh ./dragonball_array.sh === 通常配列 fighters === fighters[0]: 悟空 fighters[2]: ピッコロ 全キャラクター: 悟空 ベジータ ピッコロ クリリン トランクス キャラクター数: 5 人 === 参戦キャラクター === - 悟空 - ベジータ - ピッコロ - クリリン - トランクス === インデックス付き一覧 === [0] 悟空 [1] ベジータ [2] ピッコロ [3] クリリン [4] トランクス 追加後の要素数: 6 人 削除後の全要素: 悟空 ピッコロ クリリン トランクス 悟飯 残りのインデックス: 0 2 3 4 5 スライス [2:2]: ピッコロ クリリン
dragonball_assoc.sh
#!/bin/bash
# -----------------------------------------------
# ドラゴンボールのキャラクターで連想配列の
# 宣言・参照・ループを確認します
# ※ bash 4.0 以降が必要です
# -----------------------------------------------
# -----------------------------------------------
# 1. 連想配列の宣言(declare -A が必須)
# -----------------------------------------------
declare -A power_level
# キーと値を個別に代入します
power_level["悟空"]=9000
power_level["ベジータ"]=8000
power_level["ピッコロ"]=3500
power_level["クリリン"]=1500
power_level["トランクス"]=5000
echo "=== 連想配列 power_level ==="
# キーを指定して値を参照します
echo "悟空の戦闘力: ${power_level["悟空"]}"
echo "ピッコロの戦闘力: ${power_level["ピッコロ"]}"
echo ""
# -----------------------------------------------
# 2. 要素数と全値・全キーの展開
# -----------------------------------------------
echo "登録キャラクター数: ${#power_level[@]} 人"
# ${!map[@]} で全キーを展開します
echo "キー一覧: ${!power_level[@]}"
# ${map[@]} で全値を展開します
echo "戦闘力一覧: ${power_level[@]}"
echo ""
# -----------------------------------------------
# 3. キーと値のペアでループします
# -----------------------------------------------
echo "=== 戦闘力ランキング ==="
for chara in "${!power_level[@]}"; do
echo " ${chara}: ${power_level[$chara]}"
done
echo ""
# -----------------------------------------------
# 4. 要素の更新と削除
# -----------------------------------------------
# 既存のキーに再代入すると上書きされます
power_level["悟空"]=150000000
echo "超サイヤ人に覚醒: 悟空の戦闘力 → ${power_level["悟空"]}"
# unset でキーを削除します
unset power_level["クリリン"]
echo "クリリン削除後の要素数: ${#power_level[@]} 人"
echo ""
# -----------------------------------------------
# 5. キーの存在確認
# -----------------------------------------------
# ${map[$key]+x} でキーが存在するか確認します(存在すれば "x" が展開されます)
check_key="ベジータ"
if [[ -n "${power_level[$check_key]+x}" ]]; then
echo "${check_key} はリストに存在します(戦闘力: ${power_level[$check_key]})"
else
echo "${check_key} はリストに存在しません"
fi
chmod +x dragonball_assoc.sh ./dragonball_assoc.sh === 連想配列 power_level === 悟空の戦闘力: 9000 ピッコロの戦闘力: 3500 登録キャラクター数: 5 人 キー一覧: 悟空 ベジータ ピッコロ クリリン トランクス 戦闘力一覧: 9000 8000 3500 1500 5000 === 戦闘力ランキング === 悟空: 9000 ベジータ: 8000 ピッコロ: 3500 クリリン: 1500 トランクス: 5000 超サイヤ人に覚醒: 悟空の戦闘力 → 150000000 クリリン削除後の要素数: 4 人 ベジータ はリストに存在します(戦闘力: 8000)
${arr[@]} と ${arr[*]} の違い
| 書き方 | ダブルクォートあり | ダブルクォートなし |
|---|---|---|
${arr[@]} | 各要素を個別の引数として展開します。要素内にスペースがあっても分割されません。for ループや関数への引数渡しには "${arr[@]}" が推奨です。 | 単語分割が行われ、要素内のスペースで分割されてしまいます。 |
${arr[*]} | IFS の先頭文字(デフォルトはスペース)で全要素を結合した1つの文字列として展開します。CSV 出力などに使います。 | "${arr[@]}" のダブルクォートなしと同じく単語分割されます。 |
概要
『シェルスクリプト』の通常配列は arr=(a b c) で宣言し、${arr[n]} で要素を参照します。全要素を展開するには "${arr[@]}"、要素数を取得するには ${#arr[@]}、全インデックスを取得するには ${!arr[@]} を使います。for name in "${arr[@]}" のループではダブルクォートを忘れずに付けることで、スペースを含む要素が誤って分割されるのを防げます。連想配列は declare -A map で宣言してから map[key]=value と代入します。全キーを取り出すには ${!map[@]}、全値を取り出すには ${map[@]} を使います。キーの存在確認は ${map[$key]+x} パターンが便利です。変数の基本については 変数の基本 も合わせて参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。