1. ホーム
  2. bash

[解決済み] set -u` による Bash による空の配列展開

2022-08-14 07:41:22

質問

bashスクリプトを書いているのですが、そのスクリプトには set -u で、空の配列の展開に問題があります。bash は展開中に空の配列を未設定の変数として扱うようです。

$ set -u
$ arr=()
$ echo "foo: '${arr[@]}'"
bash: arr[@]: unbound variable

( declare -a arr も役に立ちません)

これに対する一般的な解決策は ${arr[@]-} を使うことで、("undefined") 空の配列の代わりに空の文字列を代入することです。しかし、これは良い解決策ではありません。なぜなら、1つの空の文字列を含む配列と空の配列の区別がつかなくなるからです。(bashでは@-expansionは特別で、これは "${arr[@]}""${arr[0]}" "${arr[1]}" … というように、コマンドラインを構築するための完璧なツールになります)。

$ countArgs() { echo $#; }
$ countArgs a b c
3
$ countArgs
0
$ countArgs ""
1
$ brr=("")
$ countArgs "${brr[@]}"
1
$ countArgs "${arr[@]-}"
1
$ countArgs "${arr[@]}"
bash: arr[@]: unbound variable
$ set +u
$ countArgs "${arr[@]}"
0

で配列の長さをチェックする以外に、この問題を回避する方法はあるのでしょうか? if で配列の長さをチェックする (下のコードサンプルを参照) か、あるいは -u をオフにするか?

if [ "${#arr[@]}" = 0 ]; then
   veryLongCommandLine
else
   veryLongCommandLine "${arr[@]}"
fi

更新しました。 削除された bugs タグを削除しました。

どのように解決するのですか?

この のみ 安全なイディオムは ${arr[@]+"${arr[@]}"}

Bash 4.4+ にしか関心がないのであれば別ですが、もしそうであればこの質問を見ていないでしょう :)

これはすでに推奨されている 池上さんの回答 で推奨されていますが、このスレッドでは誤った情報や推測が多いですね。他のパターン、例えば ${arr[@]-} とか ${arr[@]:0} ではない は、Bash のすべての主要なバージョンで安全ではありません。

下の表が示すように、すべての現代的なBashのバージョンで信頼できる唯一の拡張は ${arr[@]+"${arr[@]}"} です (列 +" ). 注目すべきは、Bash 4.2では他のいくつかの展開が失敗し、(残念ながら)短い ${arr[@]:0} イディオムもそうですが、これは単に間違った結果を出すだけでなく、実際に失敗します。 4.4 より前のバージョン、特に 4.2 をサポートする必要がある場合、このイディオムが唯一の動作するイディオムです。

残念ながら他の + の拡張は、一見すると同じように見えますが、実際には異なる振る舞いをします。使用する :+ の代わりに + ( :+" 表中) は機能しません。 : -展開 は、1つの空の要素を持つ配列 ( ('') ) を "null" として扱い、したがって (一貫して) 同じ結果には展開されません。

ネストされた配列の代わりに完全な展開を引用する ( "${arr[@]+${arr[@]}}" , "+ のように)、ほぼ同等であると予想されますが、4.2でも同様に安全ではありません。

このデータを生成したコードと、いくつかの追加のバージョンの bash の結果は、次のサイトで見ることができます。 この gist .