変数の未定義チェックに
Bash
シェルの-v
オプションをBourne
シェルで使うと、unknown operand
エラーが発生する。
Alpine Linux
などのBourne
系シェル(Ash
)で変数や環境変数の未定義をチェックできないか。
「bourne
シェル
未定義
確認
」とググっても、Bash
シェルの情報ばかりだったので、自分のググラビリティとして。
TL;DR
シェルの変数展開(
${}
)で、代替値(:+
)を使って検知する
# Bourne/Ash/Bash/Dash コンパチ(互換のある)構文
[ "${VAR:+defined}" ] || {
echo '変数 VAR が未定義もしくは空です。'
exit 1
}
[ "${VAR:+defined}" ] && {
echo "変数 VAR は定義されています: ${VAR}"
exit 0
}
- オンラインで動作を見る @ paiza.IO
- 参考文献:bashで[ -v "$VAR" ]を使わずに変数が未定義か判定する @ Qiita
- 参考文献:mattintosh4 さんのコメント
TS;DR
確かに Alpine Linux で bash
を使いたいならインストールすればいいだけなのです。しかし、Docker での利用なので、なるべく余計なものを入れたくない(レイヤーを作りたくない)のです。
Docker コンテナ起動時にホストからコンテナに環境変数を渡す必要がある場合、必須の環境変数がセットされていないとエラーでコンテナが起動しないようにしたいのです。
「未定義ならエラーで終了」だけならコメントいただいたように set -u
をスクリプトなどに記載するのが簡単です。ポカヨケをしたい場合は、関連するスクリプトファイルに : ${VAR?}
を記載しておくのもいいかもしれません。
任意のエラーメッセージ
ただ、今回は「未定義の場合もしくは必須項目が空の場合は任意のメッセージを表示して終了」させたいのです。
任意のメッセージとは「どのファイルに環境変数を記載すべきか」などのユーザーへの指示メッセージです。そのため判定式が必要だったのです。
下記は、変数定義の判定に -v
もしくは -z
オプションを使った方法と set
コマンドを使った方法を説明しています。
おすすめは、コメントにいただいた TL;DR の set
コマンドを使った方法で、シンプルで可読性の高い書き方だと思います。
検証環境情報
~ # cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.10.2
PRETTY_NAME="Alpine Linux v3.10"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"
~ # sh --help
BusyBox v1.30.1 (2019-06-12 17:51:55 UTC) multi-call binary.
Usage: sh [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS] / -s [ARGS]]
Unix shell interpreter
~ # bash --version
GNU bash, version 5.0.0(1)-release (x86_64-alpine-linux-musl)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
-v
オプションの場合
ググると、変数の定義確認で一番出てくる方法です。問題は Bourne/Ash シェルでは使えないことです。
~ # cat sample1.sh
#!/bin/sh
[ -v HOGE ] || {
echo 'Not defined HOGE'
exit 1
}
echo 'HOGE is defined with value:' $HOGE
~ # unset HOGE
~ # # Bash シェルで実行(正常)
~ # bash sample1.sh
Not defined HOGE
~ # # Bourne シェルで実行(エラー)
~ # sh sample1.sh
sh: HOGE: unknown operand
Not defined HOGE
~ # export HOGE=FUGA
~ # # Bash シェルで実行(正常)
~ # bash sample1.sh
HOGE is defined with value: FUGA
~ # # Bourne シェルで実行(エラー)
~ # sh sample1.sh
sh: HOGE: unknown operand
Not defined HOGE
~ # export HOGE=''
~ # # Bash シェルで実行(正常)
~ # bash sample1.sh
HOGE is defined with value:
~ # # Bourne シェルで実行(エラー)
~ # sh sample1.sh
sh: HOGE: unknown operand
Not defined HOGE
-z
オプションの場合
-v
オプションが使えない場合に -z
オプションを使った bash/bourne/ash 互換の代替法です。定義されているか否かの判定だけで、値が空の場合は真(true
)になっていることに注意ください。
~ # cat sample2.sh
#!/bin/sh
[ -z "$HOGE" ] && [ "${HOGE:-A}" = "${HOGE-A}" ] && {
echo 'Not defined HOGE'
exit 1
}
echo 'HOGE is defined with value:' $HOGE
~ # unset HOGE
~ # bash sample2.sh
Not defined HOGE
~ # sh sample2.sh
Not defined HOGE
~ # export HOGE=''
~ # bash sample2.sh
HOGE is defined with value:
~ # sh sample2.sh
HOGE is defined with value:
~ # export HOGE=FUGA
~ # bash sample2.sh
HOGE is defined with value: FUGA
~ # sh sample2.sh
HOGE is defined with value: FUGA
~ # # 🎉
シェルの変数展開で代替値を使った場合
この方法は、変数が定義済みだけでなく値が空の場合も検知できるので、必須の環境変数をチェックする際に有用だと思います。
シェルの変数展開、つまり echo "The parameter is: ${parameter}"
のように ${}
で変数を展開する際に :+
を使うアイデアです。
${parameter:+word}
と :+
を使うと ${parameter}
が NULL
以外の場合 word
に置換されます。
~ # cat sample3.sh
#!/bin/sh
[ "${HOGE:+dummy}" ] || {
echo 'Not defined HOGE or empty value'
exit 1
}
echo 'HOGE is defined with value:' $HOGE
~ # unset HOGE
~ # bash sample3.sh
Not defined HOGE or empty value
~ # sh sample3.sh
Not defined HOGE or empty value
~ # export HOGE=''
~ # bash sample3.sh
Not defined HOGE or empty value
~ # sh sample3.sh
Not defined HOGE or empty value
~ # export HOGE=FUGA
~ # bash sample3.sh
HOGE is defined with value: FUGA
~ # sh sample3.sh
HOGE is defined with value: FUGA
~ # # 🎉
参考文献
- bashで[ -v "$VAR" ]を使わずに変数が未定義か判定する @ Qiita
- Bourne Shell Tutorial @ The Grymoire
- Embedded Linux | Almquist shell @ Wikipedia
- シェルの変数展開@ Qiita
- 【 set 】コマンド(応用編2)――定義されていない変数の扱いやコマンドのエラーへの対応を変更する | Linux基本コマンドTips @ atmarkIT