シェルスクリプトで配列変数を参照する際は “${変数名}” と記述する癖をつけたほうが良い

Bash

はじめに

チームメンバがシェルスクリプトを書いていました。
変数を参照する際のちょっとした不備ではまりました。

変数をダブルクォートで囲んでいなかったことが原因だったのですが、どんなケースだったかを紹介します。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ bash -version | head -n 1
GNU bash, version 4.2.46(2)-release (x86_64-redhat-linux-gnu)

配列変数を利用してループ処理を行うケースで問題が発生

問題が発生していたのは配列変数を受け取り、ループ処理するロジックでした。

ここでは test.sh というファイル名で保存されていたとしましょう。

#!/usr/bin/env bash

LIST=(
  "111"
  "22 22 22"
  "333"
)

for TXT in ${LIST[@]}; do
  # ***実際にはこの部分にロジックが記述されていました***
  echo "${TXT}"
done

想定では、このループ処理は 3 行の文字列を出力する想定でした。

  1. 111
  2. 22 22 22
  3. 333

ところが実行結果は以下のようになりました。

$ ./test.sh
111
22
22
22
333

これは LIST という配列変数の参照の仕方に問題があったためです。

正しく "${LIST[@]}" で参照する

先の test.sh スクリプトは以下のように修正すれば想定通りの挙動をします。

#!/usr/bin/env bash

LIST=(
  "111"
  "22 22 22"
  "333"
)

# **先ほどとの違いはここ!ダブルクォートで囲んでいます。**
for TXT in "${LIST[@]}"; do
  echo "${TXT}"
done

実行結果は以下のようになります。

$ ./test.sh
111
22 22 22
333

このように、配列の各要素を参照する際には、 "${LIST[@]}" のように、ダブルクォートで囲んでやらなければスペースを含む値の場合に想定通りのループ処理をしてくれません。

変数を参照する際には "${VAR}" / "${VAR[@]}" と記述する癖をつけよう

変数を参照する際には、 "${VAR}" / "${VAR[@]}" と記述する癖をつけたほうが良いです。

こんなゆるい言語を使わなければ良い、というのも一つですが、DockerKubernetes が導入されるケースが多い昨今、Bash や Posix 準拠のシェルが活躍する場も多いです。

この点を心がけるだけで随分バグが減るはずです。

shellcheckを導入しリアルタイムでコードチェックを行う

shellcheck という、シェルスクリプトの構文チェックツール( JavacheckstylePHPPHP-CS-FixerJavaScriptESLint )を導入するのがおすすめです。

僕は Neovim を使っていますが、プラグインで容易に導入できます。
コードを書いている時にリアルタイムでエラーを表示してくれます。

ひとこと

Neovim のコードスニペットツールが大活躍しています。
VSCode や Eclipse のようなツール、IntelliJ にもスニペット登録機能があるため、活用すると "${VAR}" の記述も面倒ではならなくなります。

Bash