シェルスクリプト 配列 使い方

バイオインフォ道場、くまぞうです。

シェルスクリプト 配列

スポンサーリンク



シェルスクリプト 配列を使う場合の注意

シェルスクリプトを書く際にも、他のプログラミング言語と同じように、データの格納先を1つにまとめてインデックスによってデータ管理することができます。但し、bash 2.0 以降の機能です。もし、それよりも前のバージョンを使っている場合は、bashの最新版の利用を検討してみて下さい。

シェルスクリプト 配列 bashのバージョン確認

まずは、bashのバージョン確認を行います。シェルスクリプトで配列を使う場合は、bashのバージョンが2.0以降であることを確認します。最新版は、バージョン4.4(2017年1月)です。

$ bash --version
bash --version
GNU bash, バージョン 4.3.11(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.

シェルスクリプト 配列 bashのバージョンアップ

bashの最新版へのバージョンアップ方法として、バージョン4.4への移行方法をまとめました。

シェルスクリプト bash 最新版の利用

シェルスクリプト 配列 定義と初期化

配列は代入によって自動的に生成されます。いくつか代入方法があるので、状況に応じて使わけることができます。尚、配列のインデックスは0から始まります。インデックス最大値はかなり大きい(数千億らしい)ので、あまり気にすることはないと思います。代入に際しての注意は、=の前後に空白をいれないことです。

配列 初期化 1つずつインデックスを指定して代入

要素1つずつを指定したインデックスに格納します。要素の格納場所を正確に決めて代入したいときに使います。繰り返し処理で

# 配列 my_array1 に1つずつ代入する場合
$ my_array1[0]="name1"
$ my_array1[2]="addr1"
$ my_array1[1]="tel1"

# 配列 my_array1 の要素を1つずつ参照
$ echo ${my_array1[0]}
name1
$ echo ${my_array1[1]}
tel1
$ echo ${my_array1[2]}
addr1

配列 初期化 インデックスを指定せずにまとめて代入

配列の先頭から順にまとめて代入します。(“要素1” “要素2” “要素3”)と並べて書きますが、データの区切りは「空白」です。

# 配列 my_array2 先頭(インデックス0)から順番にまとめて代入
$ my_array2=("name2" "tel2" "addr2")

# 配列 my_array2 の要素を1つずつ参照(インデックス0から順番に)
$ echo ${my_array2[0]}
name2
$ echo ${my_array2[1]}
tel2
$ echo ${my_array2[2]}
addr2

# 配列 my_array2 の要素の格納場所を確認
$ echo ${!my_array2[@]}
0 1 2

配列 初期化 部分的にインデックスを指定してまとめて代入

要素を指定したインデックスに格納しつつ、まとめて代入します。使う機会は少ないかもしれませんので、簡単に紹介。

# 配列 my_array3 インデックスを指定しつつまとめて代入
$ my_array3=("name3" [10]="tel3" "addr3")

# 配列 my_array3 の要素の格納場所を確認
$ echo ${!my_array3[@]}
0 10 11

# 配列 my_array3 の要素を1つずつ参照
$ echo ${my_array3[0]}
name3
$ echo ${my_array3[10]}
tel3
$ echo ${my_array3[11]}
addr3

シェルスクリプト 配列 値の参照

配列 値の参照方法

配列に格納した値を参照するには、${array[index]}という書き方をします。変数の参照($var, または ${var})と似た形式です。ただし、{}が必要です。{}をつけなくても参照できますが、その場合は先頭データを意味します。

# 配列 my_array2 先頭(インデックス0)から順番にまとめて代入
$ my_array2=("name2" "tel2" "addr2")

# 配列 my_array2 の要素を1つずつ参照(インデックス0から順番に)
$ echo ${my_array2[0]}
name2
$ echo ${my_array2[1]}
tel2
$ echo ${my_array2[2]}
addr2

$ echo $my_array2
name2

配列 値の参照方法 要素の個数・要素の長さ

配列に要素が何個格納されているかを調べるには、${#array[@]}を使います。#は長さを意味します。@は特別なインデックスで、配列の全ての要素を参照します。配列の「全体の要素」に対して「長さ」を計算するので、配列の要素数を得ることができます。インデックスが飛んでも、値が格納されている個数だけが返されます。

# 配列 my_array2 まとめて代入
$ my_array2=("name2" "tel2" "addr2")

# 配列 my_array2 要素の個数
$ echo ${#array[@]}
3

# 配列 my_array2 に要素を追加(インデックス1つ飛び)
$ my_array2[4]="data"

# 配列 my_array2 要素の格納位置を確認(インデックス飛び)
$ echo ${!my_array2[@]}
0 1 2 4

# 配列 my_array2 要素の個数(追加後)
$ echo ${#my_array2[@]}
4

#は長さを意味します。#array[index]要素を指定すると、要素の長さを得ることができます。

# 配列 my_array2 要素1の内容
$ echo ${my_array2[0]}
name2

# 配列 my_array2 要素1の長さ
$ echo ${#my_array2[0]}
5

# 配列 my_array2 要素2の内容
$ echo ${my_array2[1]}
tel2

# 配列 my_array2 要素2の長さ
$ echo ${#my_array2[1]}
4

配列 値の参照方法 全体の参照 「@」 「*」

@*は特別なインデックスで、配列の全ての要素を参照します。大変便利な機能ですが、両者の使い分けは難しいかもしれません。いくつかの定型パターンを覚えて慣れていくのが良いと思います。

# 配列 my_array2 要素の個数([@]を[*]に変更しても同じ)
$ echo ${#my_array2[@]}
4

# 配列 my_array2 要素の格納位置を確認(先の例から。[*]でも同じ)
$ echo ${!my_array2[@]}
0 1 2 4

全体参照を繰り返し処理で利用した場合も、両者の違いは無いようにみえます。しかし、@*の違いが生じる場合があります。(外部からの引数などの処理で、)配列への全体参照をダブルクォーテーションで囲んだ場合、[@]では1つずつのワードで分割されて管理しますが、[*]では全てが1つのワードとして管理されます。状況に応じて使い分ける必要があります。

bash_array1.sh
#! /bin/bash

my_array=("name" "tel" "addr")

echo "case [@]"
echo "--------"
for x in ${my_array[@]}
do
    echo $x
done

echo ""

echo "case [*]"
echo "--------"
for x in ${my_array[*]}
do
    echo $x
done
実行例
# 実行権限の付与
$ chmod +x ./bash_array1.sh 

$ ./bash_array1.sh 

# 結果:[@] と [*] の動作は同じ
case [@]
--------
name
tel
addr

case [*]
--------
name
tel
addr
bash_array2.sh
#! /bin/bash

my_array=("name" "tel" "addr")

echo "case [@]"
echo "--------"
for x in "${my_array[@]}"
do
    echo $x
done

echo ""

echo "case [*]"
echo "--------"
for x in "${my_array[*]}"
do
    echo $x
done
実行例
# 実行権限の付与
$ chmod +x ./bash_array2.sh 

$ ./bash_array2.sh 

# 結果:[@] と [*] の展開結果が異なる
case [@] # 個別に扱われる
--------
name
tel
addr

case [*] # 1つに扱われる
--------
name tel addr

シェルスクリプト 配列 繰り返し処理で使う

配列はforなどの繰り返し処理で用いられることが多いです。例では、ファイル情報から実行可能ファイルをリストアップします。インデックスを指定した代入や配列の数・配列全体の表示などを行いました。

bash_for.sh

#! /bin/bash

declare -i COUNT=0
for x in $(ls *)
do
    if [ -x $x ]; then
	files[$COUNT]=$x
    fi
    COUNT=COUNT+1
done

echo "files : "${COUNT}
echo "   -x : "${#files[@]} $(echo ${files[@]} | tr ' ' ',')
# 実行権限付与
$ chmod +x ./bash_for.sh

# 実行
$ ./bash_for.sh 
files : 7
   -x : 2 bash_array.sh,bash_for.sh

シェルスクリプト 配列 削除

配列の値の削除・配列自体の削除には、unsetを使います。インデックス番号で要素を指定して用いた場合は、配列の個々の要素を削除します。[@]や[*]で全部の要素を指定することもできます。インデックスを指定しない場合は、配列そのものを削除します。

# 配列 my_array2 まとめて代入
$ my_array2=("name2" "tel2" "addr2")

# 配列 my_array2 要素の確認
$ echo ${my_array2[@]}
name2 tel2 addr2

# 配列 my_array2 要素の個数
$ echo ${#array[@]}
3

# インデックスを指定して要素を1つ削除(2番目)
$ unset my_array2[1]

# 配列 my_array2 要素の確認(tel2が削除された)
$ echo ${my_array2[@]}
name2 addr2

# 配列 my_array2 要素の個数
$ echo ${#array[@]}
2

# 配列 my_array2 要素の格納位置確認
$ echo ${!my_array2[@]}
0 2
# 特殊インデックスを指定して要素全て削除
$ unset my_array2[@]

# 配列 my_array2 要素の確認(なし)
$ echo ${my_array2[@]}

# 配列 my_array2 要素の個数(なし)
$ echo ${#my_array2[@]}
0

# 配列名を指定して要素全て削除
$ unset my_array2

# 配列 my_array2 要素の個数(なし)
$ echo ${#my_array2[@]}
0
スポンサーリンク