はじめに
本項ではbashの組み込みコマンドである local
を扱います。
変数のスコープを関数内に限定するために使用しています。
執筆のきっかけ
執筆のきっかけは以下のようなシェルスクリプトを組んでいる際にはまったことです。
function foo() {
local hoge="$(curl http://localhost/testpage)"
test "${?}" -ne 0 && return 1
echo hoge
}
foo
exit ${?}
処理の流れは以下のようなものになります。
- 関数内であるコマンドの処理結果を変数に格納
- あるコマンドが失敗した場合、リターンコードに異常終了を表す数値(例では
1
)を返却し関数を抜ける - 成功した場合のみ、後続処理を行う。
※実際にやりたかったコマンドはcurl
ではなくミドルウェア製品独自のコマンドです。失敗する可能性があり、"${?}"に0以外が格納されるコマンドをイメージしてください。
はまったこと
先述の hoge.sh
は curl http://localhost/testpage
が失敗しても "${?}"
は常に 0
が格納されます。
よって、return 1
が機能することはありませんでした。
はまった原因
「$?
は直前のコマンドの終了値を格納する」という定義の通り、bashの local
コマンドの終了値を格納し続けていたため、$?
が常に0になっていました。
対処方法
man local
を参照すると「local [option] [name[=value] ...]」との記載があるので、変数名のみで宣言が可能そうと気づきました。
以下のようなスクリプトを作成、実行したところ、想定通りに動作しました。
#!/bin/bash
## FUNCTIONS ##
function foo() {
local hoge
hoge="$(bash -c "exit 1")"
local rc="${?}"
echo "local.hoge: ${hoge}"
echo "local.hoge.rc: ${rc}"
}
## MAIN ##
hoge="fugafuga"
foo
echo "global.hoge: ${hoge}"
$ ./test.sh
local.hoge:
local.hoge.rc: 1
global.hoge: fugafuga
おわりに
些細なことですがバグの原因になるところでした。
local
を利用して変数の宣言と同時にコマンドの出力を変数に代入しエラーハンドリングを行う場合は、「変数宣言」、「値の代入」を別々に行うことでコマンドのリターンコードを"${?}"
で拾えるようになります。