Shell Script(Bash)でよく使うパターン

シェル変数に値がセットされているかどうかを確認する
-
このスクリプトでは、シェルスクリプトの配列を使っています
-
シェル変数に値がセットされているかどうかを調べる関数で作成する関数
check_if_variable_set
を使います -
スクリプト中で定義されているシェル変数を自動的に全て検出して調べるのは難しいので、妥協して「シェルスクリプトの配列に、調べたい変数名を羅列する」という形を取っています
-
値がセットされていないシェル変数があった場合、標準エラー出力にエラーメッセージとして値がセットされていない変数名をリストし、終了コード
1
でスクリプトを終了させています
# 値がセットされているかどうかを確認するシェル変数の変数名を、シェルスクリプトの配列で羅列
# 区切り文字はスペースで、カンマ(,)ではないことに注意
script_variables=(
"foo" "bar" "baz"
)
# エラーメッセージで「値がセットされていない変数名」をリストするための配列
unset_script_variables=()
for script_variable in "${script_variables[@]}"; do
# 値がセットされていないシェル変数名を、unset_script_variablesに格納
check_if_variable_set "${script_variable}" || unset_script_variables+=("${script_variable}")
done
if [ "${#unset_script_variables[@]}" -gt 0 ]; then
echo -e "[ NG ] Variables listed below are unset in $0:" 1>&2 # $0はこのシェルスクリプトのファイルパス
for unset_script_variable in "${unset_script_variables[@]}"; do
echo -e " x ${unset_script_variable}" 1>&2
done
echo ""
exit 1
fi
出力例:

前提とする環境
- Bash
前提で必要となる知識
- 標準出力、標準エラー出力と、リダイレクト先の変更
- シェルスクリプトの配列とその操作
- シェル関数の定義

シェル関数
使いまわしそうなものを、シェル関数にしています。
複雑そうなものにはコメント文も併記していて、使用例もそこに書いています。
コメント文の書式はRubyのYARDの文法に寄せていますが、筆者が見やすいというだけで、実用的な意味はないです。
1
で終了する
あるコマンドがインストールされているかどうかを調べ、インストールされていない場合はエラーメッセージを出力して終了コード# Displays an error message and returns 1 if the command is not installed.
#
# @note The command is assumed to have --version option.
# @example
# check_if_command_installed pwd
# #=> ""
# check_if_command_installed some_uninstalled_command
# #=> "[ NG ] Install some_uninstalled_command on this host."
check_if_command_installed() {
local command_name="$1"
command -v "${command_name}" > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo -e "[ NG ] Install ${command} on this host." 1>&2
echo ""
exit 1
fi
}
より詳しい解説
-
command -v <コマンド>
を実行してみる。- コマンドがインストールされていれば、コマンドのパス・エイリアス定義が出力され、終了コード
0
が変数$?
にセットされる - コマンドがない場合は、出力はなく、終了コード
1
が変数$?
にセットされる
- コマンドがインストールされていれば、コマンドのパス・エイリアス定義が出力され、終了コード
-
command -v <コマンド>
の出力・エラー出力は必要ないので、/dev/nullに捨てる - 終了コードが
0
ではない場合、コマンドがインストールされていないということで、エラーメッセージを標準エラー出力に出力する
シェル変数に値がセットされているかどうかを調べる
"${!variable_name}"
の部分は、Bashのシェル変数展開の「間接展開」を利用しています。
具体的には、以下のような動きになっています:
#!/bin/bash
foo="FOO"
str_foo="foo"
echo "${!str_foo}"
chmod 755 indirect_expansion_labo.sh
./indirect_expansion_labo.sh
#=> FOO
例として、あらかじめvariable_name="foo"
としているとします。
-
"${!variable_name}"
の"${}"
の中身が、エクスクラメーションマーク!
で始まっている(!variable_name
)ので、まず変数の間接展開が行われることになる -
!variable_name
の部分は、変数variable_name
に入っている文字列foo
で置換される。
つまり、"${!variable_name}"
が"${foo}"
になる - あとは(ああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ)間接参照の終了か
- 結局、
"${!variable_name}"
の値は、シェル変数foo
の値になる
分岐の図を描いた方がわかりやすいな。
この動作は、man bash
のParameter Expansion
のセクションに記載されています。
Parameter Expansion
The `$' character introduces parameter expansion, command substitution, or arithmetic expansion. The parameter name or symbol to be expanded may be enclosed in braces, which are optional but serve to protect the variable to be expanded from characters immediately following it which could be interpreted as part of the name.
When braces are used, the matching ending brace is the first `}' not escaped by a backslash or within a quoted string, and not within an embedded arithmetic expansion, command substitution, or parameter expansion.
${parameter}
The value of parameter is substituted. The braces are required when parameter is a positional parameter with more than one digit, or when parameter is followed by a character which is not to be interpreted as part of its name. The parameter is a shell parameter as described above PARAMETERS) or an array reference (Arrays).
If the first character of parameter is an exclamation point (!), and parameter is not a nameref, it introduces a level of indirection. Bash uses the value formed by expanding the rest of parameter as the new parameter; this is then expanded and that value is used in the rest of the expansion, rather than the expansion of the original parameter. This is known as indirect expansion. The value is subject to tilde expansion, parameter expansion, command substitution, and arithmetic expansion. If parameter is a nameref, this expands to the
name of the parameter referenced by parameter instead of performing the complete indirect expansion. The exceptions to this are the expansions of ${!prefix*} and ${!name[@]} described below. The exclamation point must immediately follow the left brace in order to introduce indirection.
...
# Returns 0 if the variable is defined and set, otherwise returns 1.
#
# @example
# foo="some string is set"
# bar="" # no value is set
# # baz="" # not defined
#
# check_if_variable_set "foo" || echo "shell variable 'foo' is not set."
# #=> ""
# check_if_variable_set "bar" || echo "shell variable 'bar' is not set."
# #=> "shell variable 'bar' is not set."
# check_if_variable_set "baz" || echo "shellvariable 'baz' is not set."
# #=> "shell variable 'baz' is not set."
check_if_variable_set() {
local variable_name="$1"
test -n "${!variable_name}"
}