シェルスクリプトの基礎 - 配列
概要
シェルスクリプトにおいて、配列を使用する方法を記載する。
配列の定義
配列を定義するには、以下のように記述する。
array[0]=a
array[1]=b
array[2]=c
または、以下のように記述する。
array=(a b c)
配列の基本
以下の例では、0〜3番目(2番目を除く)までの要素の配列を定義した後、各要素と配列全体を出力している。
#!/bin/sh
array[0]=a
array[1]=b
array[3]=d
# 0番目の要素を参照する
echo "$array"
# 1番目の要素を参照する
echo "$array[1]"
# 2番目の要素は存在しないので空文字となる
echo "$array[2]"
# 3番目の要素を参照する
echo "$array[3]"
# 全要素を参照する
echo "$array[@]"
# 出力
a
b
d
a b d
配列の要素の追加
配列に要素を追加する場合、新たな添字を指定して値を代入する。
また、配列に配列を追加する場合、+=
を使用して配列名+=(値 値 値...)
のように記述する。
#!/bin/bash
array=(a b c d)
# 配列arrayの4番目の要素に代入
array[4]=e
# 配列arrayの末尾に要素を代入
array+=(f g)
# 配列arrayの末尾に要素を代入(ただし、添字が0から1ずつ値が存在する場合のみ可能)
array[${#array[@]}]=h
for i in "${!array[@]}"
do
echo "$i" "${array[$i]}"
done
# 出力
0 a
1 b
2 c
3 d
4 e
5 f
6 g
7 h
配列の要素の削除
以下の例では、配列を定義した後、unset
コマンドにより0番目の要素を削除している。
#!/bin/sh
array[0]=a
array[1]=b
unset array[0]
echo "$array[@]"
# 出力
b
配列の要素数の表示
配列の要素数を表示するには、${#変数名[@]}
を使用する。
#!/bin/sh
array=(a b c d)
echo "${#array[@]}"
# または
echo "${#array[*]}"
# 出力
4
4
配列と繰り返し
以下の例では、括弧()
を使用して配列を定義した後、for
文を使用して配列の要素を出力している。
#!/bin/sh
array=(a b c d)
for e in $array[@]
do
echo "element = $e"
done
# 出力
element = a
element = b
element = c
element = d
また、以下のように記述することもできる。
#!/bin/sh
array=(a b c d)
for ((i=0; i<${#array[@]}; i++))
do
echo "element = $array[i]"
done
# 出力
element = a
element = b
element = c
element = d
配列の要素がスペースを含んでいる場合は、以下のように、配列をダブルクォーテーションで括る。
#!/bin/sh
array=(1 2 3 4 5 "6 6")
for i in "${array[@]}"
do
echo "${i}"
done
# 出力
1
2
3
4
5
6 6
配列の再生成
元の配列に対して、追加する値を配列化して再生成する方法がある。
以下の例では、配列への要素の追加ではなく配列の再作成を行っているため、不連続だったインデックスも再作成され、通常通り0からの連番となる。
# インデックスが不連続な配列を作成する
array[0]="hoge"
array[2]="piyo"
array[4]="fuga"
echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
# 全要素と追加する値を配列化して再生成する
# 不連続だったインデックスが連続したものに変化する
array=("${array[@]}" "foo" "bar" "bazz")
echo "${array[0]}, ${array[1]}, ${array[2]}, ${array[3]}, ${array[4]}, ${array[5]}"
# 出力
hoge, , piyo, , fuga,
hoge, piyo, fuga, foo, bar, bazz
配列の要素をソートする
文字列としてソートする
配列の全要素を出力した上で、sort
コマンドでソートを実行して、実行結果を配列に格納する。
まず、配列の要素に空白が含まれる場合を考慮して、IFSを改行のみに変更する。
これは、ソートした配列を生成する時、空白区切りで要素が設定されることを防ぐ。
次に、各要素をecho
コマンドで出力することで、全要素が改行区切りで出力されるため、sort
コマンドによるソートが可能になる。
#!/bin/sh
IFS_BACKUP="$IFS"
IFS="\n";
array=("222 222" "ccc ccc" "aaa aaa" "111 111" "bbb bbb" "333 333")
array=$(for item in "${array[@]}"; do echo "$item"; done | sort)
for element in "${array[@]}"
do
echo ${element}
done
IFS="$IFS_BACKUP"
# 出力
111 111
222 222
333 333
aaa aaa
bbb bbb
ccc ccc
数値としてソートする
要素を数値としてソートするには、sort
コマンドに-n
オプションを指定する。
#!/bin/sh
IFS_BACKUP="$IFS"
IFS="\n";
array=(2 3 04 000 001)
array=$(for item in "${array[@]}"; do echo "$item"; done | sort -n)
for element in "${array[@]}"
do
echo ${element}
done
IFS="$IFS_BACKUP"
# 出力
000
001
2
3
04
連想配列
連想配列の定義は、declare -A <配列名>
と記述する。
例えば、連想配列arrayを定義する場合は、declare -A array
と記述する。
通常の配列は、declare -a <配列名>
と記述する。通常の変数は、declare <変数名>
とする。
連想配列の値は、連想配列名[キー]=値
と記述する。
例えば、連想配列arrayにおいて、キーhogeに値10を代入する場合、array["hoge"]=10
と記述する。
引用符""
または''
を省略して、array[hoge]=10
と記述してもよい。
値の参照は、通常の配列と同様に${array["hoge"]}
と記述する。ここでも、引用符""は省略できる。
for文で配列の値を全て参照する場合も、通常の配列と同様、for <変数名> in ${配列名[@]}
と記述できる。
全てのキーの値を参照する場合、配列名の前に!
記号を付加して、for <変数名> in ${!配列名[@]}
と記述する。
以下の例では、連想配列arrayを定義して、hoge、piyo、fugaの点数を保存している。
1つ目のfor文では、全員の値を順次表示して、2つ目のfor文では、全員の名前と値(キーと値)を表示している。
#!/bin/sh
declare -A array
array["hoge"]=10
array["piyo"]=20
array["fuga"]=30
for VALUE in ${array[@]}
do
echo "$VALUE"
done
echo ""
for KEY in ${!array[@]}
do
echo "key : $KEY"
echo "value : ${array[$KEY]}"
done
# 出力
10
20
30
key : hoge
value : 10
key : piyo
value : 20
key : fuga
value : 30
連想配列の値の変更
連想配列において、既存のキーを指定して値を代入する場合は値の変更、新しいキーを指定して値を代入する場合は値の追加となる。
#!/bin/sh
declare -A array
array["hoge"]=10
array["piyo"]=20
array["fuga"]=30
for KEY in ${!array[@]}
do
echo "key : $KEY"
echo "value : ${array[$KEY]}"
done
echo "== Change =="
array["hoge"]=400 #キーhogeの値の変更
array["piyo"]=500 #キーpiyoと値の追加
for KEY in ${!array[@]}
do
echo "key : $KEY"
echo "value : ${array[$KEY]}"
done
# 出力
key : hoge
value : 10
key : piyo
value : 20
key : fuga
value : 30
==change==
key : hoge
value : 400
key : piyo
value : 500
key : fuga
value : 30
連想配列に値をまとめて代入
連想配列に値をまとめて代入する場合、配列名=([キー]=値 [キー]=値)
のように、キーと値のペアで代入する。
連想配列の末尾にキーと値を追加する場合は、+=
を使用して配列名+=([キー]=値 [キー]=値)
と記述する。
# 連想配列arrayを定義
declare -A array
# 連想配列arrayに値を代入
array=(["hoge"]=10 ["piyo"]=20 ["fuga"]=30)
for KEY in "${!array[@]}"
do
echo "$KEY ${array[$KEY]}"
done
# 連想配列arrayの末尾にキーと値をまとめて代入
array+=(["hoge"]=15 ["foo"]=40)
for KEY in "${!array[@]}"
do
echo "$KEY ${array[$KEY]}"
done
# 出力
hoge 10
piyo 20
fuga 30
piyo 20
fuga 30
hoge 15 # キーhogeの値が変更される
foo 40 # キーfooと値が追加される
連想配列のコピー
連想配列のコピーは、個々のキーと値をコピーする必要がある。
なお、この方法は、連想配列ではない通常の配列にも使用できる。
declare -A array1
declare -A array2
# 連想配列array1の定義
array1["NG"]="red"
array1["OK"]="green"
# 連想配列array2に連想配列array1をコピー
for i in ${!array1[@]}
do
array2[$i]=${array1[$i]}
done
echo ${array1[@]} # array1のキーと値(redとgreen)が表示される
echo ${array2[@]} # 上と同じ内容が表示される
echo ${!array1[@]} # 連想配列array1のキー(NGとOK)が表示される
echo ${!array2[@]} # 上と同じ内容が表示される
echo ${array1["NG"]} # redが表示される
echo ${array2["OK"]} # greenが表示される
declare -a week1 # 通常の配列week1を定義
declare -a week2 # 通常の配列week2を定義
week1=(Sun Mon Tues Wed Thur Fri Sat)
# 通常の配列のコピー
for i in ${!week1[@]}
do
week2[$i]=${week1[$i]};
done
echo ${week1[@]}
echo ${week2[@]}