LoginSignup
7
6

More than 5 years have passed since last update.

Bash に住む妖怪 〜 空配列

Last updated at Posted at 2018-10-10

結論

Bash に空の配列は無い。空の配列を値に持つと変数は unset される。unset された変数を空の配列として扱いたいなら set -u をしないか、set -u するなら "${array[@]+"${array[@]}"}" という表現を使う。

(この記事で使っている Bash は 4.3.48 である。Ubuntu 16.04 で実行。)

空の配列

Bash には配列が用意されていて、以下のように使う。

words=(foo bar baz)
for w in "${words[@]}"; do
    echo "( $w )"
done

これを実行すると以下のようになる。

( foo )
( bar )
( baz )

これは当然、配列が空の場合も動作すると期待するだろうし、実際動作しているように見える。

words=()
for w in "${words[@]}"; do
    echo "( $w )"
done

しかしシェルスクリプトを書くときに常用する set -u (代入していない変数を使うとエラーで停止)を使うと...

set -u
words=()
for w in "${words[@]}"; do
    echo "( $w )"
done

bash: line 3: words[@]: unbound variable

declare を使って明示的に配列と宣言しても駄目。

set -u
declare -a words=()
for w in "${words[@]}"; do
    echo "( $w )"
done

bash: line 3: words[@]: unbound variable

仕様をチェック

そこで、man bash (1) をチェックしてみよう。空の配列のはっきりした説明は出てこないが、以下のような記述がある。

An array variable is considered set if a subscript has been assigned a value. The null string is a valid value.

要素を持たない配列変数は unset のようだ(はっきりと書いているわけではないが)。

実際、明示的に要素を削除して空配列にすると unset になるのが観測できる。

set -u
words=(foo)
unset words[0]
echo $words

bash: line 4: words: unbound variable

対処法

配列が空のとき ${words[@]} という表現が、words が unset なのでエラーになる。よって set のときのみ ${words[@]} が評価されるようにすればいい。こういうとき Bash では ${var+var} という表現を使う。

set -u
words=()
for w in "${words[@]+"${words[@]}"}"; do
    echo "( $w )"
done

配列の要素数を数える表現はそのまま使える。

set -u
words=()
echo ${#words[@]}

0

後記

そのまんまの質問が Stackoverflow にあった : Bash empty array expansion with set -u - Stack Overflow

この記事によると Bash 4.4 では ${words[@]} が unset のときにエラーにならずに空配列として扱えるようだ。ただし man の記述はそのままらしいので、Bash のバグか man のバグかは不明の由。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6