ユーニックス総合研究所

  • home
  • archives
  • bash-array

Bashの配列の使い方: 要素の参照、追加、削除。要素数の取得など

  • 作成日: 2020-08-20
  • 更新日: 2023-12-25
  • カテゴリ: Bash

Bashの配列の使い方

Bashでは配列が使えます。
複数の値を1つの変数に格納して持ち運びたい時などによく使われます。

Bashの配列は↓のように使います。

# 配列を作成する  
arr=(1 "cat" 3)  

# 配列内の1番目の要素を参照する  
echo ${arr[1]}  
# cat  

この記事ではBashの配列について具体的↓のコンテンツで見ていきたいと思います。

  • 配列とは
  • 配列を作る
  • 配列の要素を参照する
  • 配列の要素に値を設定する
  • 配列に要素を追加する
  • 配列の長さを取得する
  • 配列の要素を削除する
  • 変数を配列に変換
  • 配列をfor文で回す (1)
  • 配列をfor文で回す (2)
  • Bashの配列の使用例
  • 問題

配列とは

そもそも配列とはなんでしょうか。
プログラミング言語における配列とは、データ構造の1つです。
データ構造とはデータを管理する構造のことで、複数のデータを1つにまとめて管理したい時に使われます。

データ構造には配列やリスト、ハッシュマップなどいろいろありますが、配列はその中でも基本的なデータ構造の1つであると言えます。
データ全体のことを配列といい、全体の中の1つのデータの部分を要素と言います。
つまり要素を複数持っているのが配列です。

配列の特徴としては、隣り合う要素がメモリ上で連続していることが挙げられます。
(言語の実装によりますが、たいていはこの特徴を持っているのが配列です)
要素1つのバイト数が決まっていて、そのバイト数の領域がメモリ上で連続しているのが配列です。
このため、添字(インデックス)などの整数で即座に要素のデータにアクセスすることが出来るので、非常に高速です。

配列は可変長のデータ構造です。
可変長とは配列が伸び縮みできるということです。
このため配列に新しくデータ(要素)を追加したり、逆に配列からデータを取り除いたりと、自由に配列の中身を変更することが可能です。
可変長なので、配列へのデータの追加はメモリが許す限り行うことができます。

配列はプログラミングでは非常によく使うデータ構造です。
これが実装されていないプログラミング言語のほうが珍しいと言えるぐらい、現代ではポピュラーなデータ構造です。
配列を理解し、使えるようになることで現代的なプログラミングが可能になります。
そのためプログラミング言語を学んだ次は、最初に学ぶべきデータ構造とも言えます。

配列を作る

Bashの配列は↓のようなフォーマットで作成します。
変数(配列名)にイコール(=)を付けて、その次にカッコを書き、その中に配列の要素を書きます。

配列名=(要素1 要素2 要素3)  

空の配列を作るには↓のようにします。
カッコだけにして中身の要素を省略すると空の配列になります。

arr=()  

配列の作成時に要素を指定する場合は↓のように半角スペースで区切って書きます。

arr=(1 "cat" 3)  

配列の要素には整数や文字列などのオブジェクトを与えることができます。
注意点として変数名とイコール、カッコの間には半角スペースを書かないようにしましょう。
イコールの前後に半角スペースを書くと↓のようにエラーになります。

sample.sh: line 1: syntax error near unexpected token `('  
sample.sh: line 1: `arr = (1 "cat" 3)'  

配列の要素を参照する

配列の要素を参照するときは↓のようなフォーマットを使います。
ダラー($)をつけてブレース({})で配列を囲います。
配列名には角カッコ([])をつけて、その中に配列の要素の添字(インデックス)を書きます。

${配列名[インデックス]}  

インデックスに@を指定すると配列全体、添え字を指定すると指定した要素が出力されます。
添え字は0からはじまります(0オリジン)。

# 配列を作成する  
arr=(1 2 3)  

# インデックスが無い場合は先頭の要素のみ取得される  
echo $arr  
# 1  

# 配列内の要素をすべて取得して表示する  
echo ${arr[@]}  
# 1 2 3  

# 配列内の各要素を参照する  
echo ${arr[0]}  
echo ${arr[1]}  
echo ${arr[2]}  
# 1  
# 2  
# 3  

配列の添字を使ったアクセスでは、添字は配列内の要素の位置を表しています。
配列全体が3つの要素で作られていたら、アクセスできる添字は0, 1, 2の3つになります。
0オリジンであることに注意してください。
余談ですが、1オリジンのプログラミング言語もあります。

Bashの配列で特徴的なのは@を使った配列全体の参照です。
これはfor文で配列を回すときなどに使われる、実用的な文です。

配列の要素に値を設定する

配列の要素を上書きしたい場合は↓のようなフォーマットになります。
配列名に角カッコ([])をつけ、その中に要素の添字を指定します。
イコールをはさんで右側に要素に設定したい値を書きます。

配列名[インデックス]=値  

これもイコールの前後に半角スペースを書くとエラーになります。
例えば要素が3つ入った長さ3の配列の1番目の要素を上書きしたい場合は↓のようにします。

arr=(1 2 3)  
arr[1]="cat"  

echo ${arr[@]}  
# 1 cat 3  

このように配列内の要素は、別の値で上書きすることが可能です。
上書きすることで配列を更新することが出来るので、さまざまなプログラムのシーンで役に立ちます。

🦝 < これがないとね配列は

配列に要素を追加する

配列に要素を追加したい場合は↓のようなフォーマットになります。
配列名(変数名)に+=をつけて、その次にカッコ(())を書いてその中に値を書きます。
カッコをつけるところが他のプログラミング言語ではあまり見られない特徴的な点です。

配列名+=(値)  

これも+=の前後に半角スペースを書くとエラーになります。
たとえば↓のように長さ3の配列に新しく値(要素)を追加すると、その長さは全体で4になります。

arr=(1 2 3)  
arr+=(4)  

echo ${arr[@]}  
# 1 2 3 4  

複数の要素を追加する場合はカッコの中に複数の値を指定します。

配列名+=(値 値 値)  

たとえば↓のように、(1 2 3)で初期化された配列に対して(4 5)を追加すると、その結果は(1 2 3 4 5)になります。

arr=(1 2 3)  
arr+=(4 5)  

echo ${arr[@]}  
# 1 2 3 4 5  

複数の値をまとめて追加したい時に便利な方法です。

変数を配列に追加する場合は↓のようなフォーマットになります。

配列名+=($変数名)  

または  

配列名+=("$変数名")  

変数の文字列にスペースが含まれている場合、参照時にダブルクオートで囲まないとスペースがチョップされて分解されます。
スペースをチョップさせたくない場合は変数を"$変数名"のようにダブルクオートで囲みます。

スペースがチョップされる場合↓。

arr=(1 2 3)  
str="The cat"  

arr+=($str)  

echo ${#arr[*]}  
# 5  

echo ${arr[@]}  
# 1 2 3 The cat  

↑の例ではThe catの値の半角スペースがチョップされて配列arrに追加されています。
その結果、配列全体の長さが5になっています。

スペースがチョップされない場合↓。

arr=(1 2 3)  
str="The cat"  

arr+=("$str")  

echo ${#arr[*]}  
# 4  

echo ${arr[@]}  
# 1 2 3 The cat  

↑の例ではThe catはチョップされず、そのまま1つの要素として配列に追加されています。
その結果、配列arrの長さは4になっています(チョップされた場合は5)。

配列の長さを取得する

配列の長さの取得は↓のようなフォーマットになります。
$をつけブレース{}で囲み、配列名に#を付けます。
配列名のお尻に角カッコ([])をつけ、その中に*@を書きます。

${#配列名[*]}  

または  

${#配列名[@]}  

なかなかファンキーな記法で、覚えるのが大変です。
↓のように配列の長さを取得できます。

arr=(1 2 3)  

echo ${#arr[*]}  
# 3  

echo ${#arr[@]}  
# 3  

ちなみに*@のどちらでも配列の長さを取れるようです。
これらの違いについては調べましたがわかりませんでした。

配列の要素を削除する

配列の特定の要素の削除は↓のようなフォーマットになります。
unsetキーワードを書き、その横に配列名、角カッコの中に添字を書きます。

unset 配列名[インデックス]  

↑のようにすると参照した添字の配列の要素を削除できます。
↓は配列の1番目の要素(値は2)を削除しています。

arr=(1 2 3)  

# 2 を削除  
unset arr[1]  

echo ${arr[@]}  
# 1 3   

変数を配列に変換

変数の配列への変換は↓のようなフォーマットになります。

変数=値  

配列名=($変数)  

または  

配列名=("$変数")  

文字列の入った変数を$で参照し、配列に変換すると、文字列内のスペースがチョップされて文字列が分割されます。

str="The cat human"  
arr=($str)  

echo ${arr[@]}  
# The cat human   

# 要素数は?  
echo ${#arr[*]}  
# 3  

チョップされないようにするには変数の参照時にダブルクオートで囲みます。
↓の場合arr=("$str")の所に注目してください。

str="The cat human"  
arr=("$str")  

echo ${arr[@]}  
# The cat human   

# 要素数は?  
echo ${#arr[*]}  
# 1  

このテクニックはfor文で配列を回す時にも使いますので覚えておいてください。

配列をfor文で回す (1)

配列をfor文で回す場合は↓のようなフォーマットになります。

for 要素 in ${配列名[@]}; do  
    処理  
done  

または  

for 要素 in "${配列名[@]}"; do  
    処理  
done  

${配列名[@]}のように配列の要素をすべて参照し、それをfor文に渡します。
参照するときにダブルクオートで囲むかどうかで要素の参照方法が変わります。
ダブルクオートで囲む場合は文字列のスペースはチョップされませんが、囲まない場合はスペースがチョップされます。

arr=(1 "The cat" 3)  

for el in ${arr[@]}; do  
    echo $el  
done  
# 1  
# The  
# cat  
# 3  

for el in "${arr[@]}"; do  
    echo $el  
done  
# 1  
# The cat  
# 3  

特に意図しない限りはダブルクオートで囲むようにするといいでしょう。

配列をfor文で回す (2)

添え字を使ったfor文で配列を参照するには↓のようにします。

arr=(1 "The cat" 3)  

for ((i=0; i<${#arr[*]}; i++)); do  
    echo ${arr[$i]}  
done  

${#arr[*]}で配列の要素数を参照し、その値より下の間だけfor文を回し、その添え字で配列の要素を参照します。
for inに比べると冗長な書き方ですが、こちらもよく使いますよね。

Bashの配列の使用例

Bashの配列の使用例です。

1~10の間の値を配列に格納する

for文の添え字を配列に追加していくサンプルです。

arr=()  

for ((i=0; i<10; i++)); do  
    arr+=($i)  
done  

echo ${arr[@]}  
# 0 1 2 3 4 5 6 7 8 9  

このコードはBashの場合は↓のように書くことで代替することも出来ます。

arr=({1..10})  

echo ${#arr[*]}  
# 10  

echo ${arr[@]}  
# 1 2 3 4 5 6 7 8 9 10  

配列でスタックを再現する

配列への値の追加と削除を使ってスタックの動作を再現します。

arr=()  

push() {  
    arr+=($1)  
    echo pushed: $1  
}  

pop() {  
    local el=${arr[-1]}  
    unset arr[-1]  
    echo popped: $el  
}  

push 1  
push 2  
push 3  

pop  
pop  
pop  

# pushed: 1  
# pushed: 2  
# pushed: 3  
# popped: 3  
# popped: 2  
# popped: 1  

lsの結果を配列にしてfor文で回す

コマンドをバッククオートで囲むとそのコマンドの標準出力を参照することが出来ます。
出力をカッコで囲めば配列に変換することが可能です。
ただしファイル名にスペースが含まれている場合はスペースがチョップされます。

arr=(`ls`)  

for fname in "${arr[@]}"; do  
    echo $fname  
done  

関数に配列の要素を展開して渡す

関数の引数に配列の要素を展開して渡します。

arr=(1 2 3)  

function hi() {  
    echo $1  
    echo $2  
    echo $3  
}  

hi ${arr[@]}  
# 1  
# 2  
# 3  

問題

Q1: Bashの配列の要素の参照方法として適切なものを答えよ

  1. ${#arr[*]}
  2. ${arr[0]}
  3. ${arr[@]}

Q2: Bashの配列の長さを取得する方法として適切なものを答えよ

  1. ${arr[@]}
  2. ${#arr[@]}
  3. ${#arr[*]}

Q3: Bashの配列の要素を参照するときに、文字列のスペースをチョップさせない方法として適切な方法を答えよ

  1. シングルクオートで囲む
  2. ダブルクオートで囲む
  3. バッククオートで囲む

答え

Q1: 2, 3
Q2: 2, 3
Q3: 2