シェルスクリプトにおける配列の定義と操作手法

配列の定義方法

括弧内に要素を列挙

最も一般的な定義方法です。要素をスペースで区切って記述します。

nums=(100 200 300 400 500)
echo ${nums[@]}

インデックスを明示して定義

任意のインデックスに値を直接割り当てます。連続している必要はありません。

data=([0]=1 [1]=2 [5]=6)
echo ${data[@]}

変数の展開を利用して定義

文字列として定義したリストを配列に変換します。

str_items="apple banana cherry"
fruits=($str_items)
echo ${fruits[@]}

要素を個別に代入

インデックスごとに別々の行で代入します。

colors[0]="red"
colors[1]="green"
colors[2]="blue"
echo ${colors[@]}

配列の基本操作

要素の参照

特定のインデックスや、配列全体の要素を取得します。インデックスを省略すると最初の要素が返ります。

echo ${fruits}      # 最初の要素
echo ${fruits[1]}   # インデックス1の要素
echo ${fruits[@]}   # 全要素
echo ${fruits[*]}   # 全要素

インデックスの一覧取得

変数名の前に!を付けると、値ではなくインデックスのリストを取得できます。

echo ${!fruits[@]}

配列の長さ(要素数)の取得

変数名の前に#を付けると要素数をカウントします。

echo ${#fruits[@]}

配列のスライス(部分抽出)

${配列名[@]:開始位置:個数}の形式で、配列の一部を抽出します。

arr=(10 20 30 40 50)
echo ${arr[@]:2:2}  # 30 40

要素の置換

パターンマッチによる置換が可能ですが、元の配列は変更されません。永続的に変更するには再代入が必要です。

vals=(1 2 3 4 5)
echo ${vals[@]/3/99}  # 1 2 99 4 5
echo ${vals[@]}       # 1 2 3 4 5 (元のまま)

要素の削除

unsetコマンドを使用します。特定の要素か、配列全体を削除できます。

unset vals[2]  # インデックス2を削除
unset vals     # 配列全体を削除

要素の追加

いくつかの方法で要素を追加できます。

  • 配列名[インデックス]=値
  • 配列名[${#配列名[@]}]=値 (末尾に追加)
  • 配列名=("${配列名[@]}" 値1 値2) (ダブルクォーテーション必須。スペース含む要素の分割を防ぐため)
  • 配列名+=(値1 値2)

関数への配列渡し

関数の引数として配列変数をそのまま渡すと、最初の要素しか渡されません。全体を渡すには${配列名[@]}として展開し、関数側で再構成する必要があります。

process_array() {
  local reconstructed=("$@")
  echo "再構成: ${reconstructed[@]}"
}

items=("first item" "second item" "third item")
process_array "${items[@]}"

応用:配列の疎密判定

配列の要素数と最大インデックスを比較することで、欠落のない完全な(密な)配列かどうかを判定できます。

#!/bin/bash
check_density() {
  local arr=("$@")
  local len=${#arr[@]}
  local max_idx=$((${#arr[@]} - 1))
  
  # 実際の最大インデックスを取得
  local actual_max_idx=$(echo ${!arr[@]} | tr ' ' '\n' | sort -n | tail -n 1)
  
  if [ "$max_idx" -eq "$actual_max_idx" ]; then
    echo "密な配列です"
  else
    echo "疎な配列です(欠落あり)"
  fi
}

dense=(10 20 30 40)
sparse=([0]=10 [2]=30 [5]=50)

check_density "${dense[@]}"
check_density "${sparse[@]}"

配列のソートアルゴリズム

バブルソート

隣接する要素を比較し、大小関係が逆であれば交換する処理を繰り返すアルゴリズムです。

#!/bin/bash
nums=(5 3 8 1 2)
len=${#nums[@]}

for ((i=0; i<len-1; i++)); do
  for ((j=0; j<len-i-1; j++)); do
    if [ ${nums[$j]} -gt ${nums[$((j+1))]} ]; then
      tmp=${nums[$j]}
      nums[$j]=${nums[$((j+1))]}
      nums[$((j+1))]=$tmp
    fi
  done
done
echo ${nums[@]}

選択ソート

基準となる位置の要素とその他の要素を比較し、条件を満たす要素と交換を繰り返すことでソートを行います。バブルソートとは異なり、隣接要素の比較ではなく、指定した位置との比較・交換が行われます。

リバースソート(反転)

配列の先頭と末尾の要素を交換し、中央に向かって順に処理を進めることで要素を反転させます。

#!/bin/bash
items=(a b c d e)
cnt=${#items[@]}
for ((i=0; i<cnt/2; i++)); do
  swap=${items[$i]}
  items[$i]=${items[$cnt-$i-1]}
  items[$cnt-$i-1]=$swap
done
echo ${items[@]}

タグ: ShellScript bash Array Algorithm

6月26日 18:26 投稿