`&&` と `||` のショートサーキット評価を利用したトリッキーな bash script の書き方
tl;dr
次のような処理を行う関数を考える。
成功した時は "succeed" を出力して、終了コードは `0`
失敗した時は "failed" を出力して、終了コードは `1`
次に書いた straight
関数と tricky
関数の挙動は同じ。
straight() {
if $(run-command) ; then
echo "succeed"
return 0
else
echo "failed"
return 1
fi
}
tricky() {
{ $(run-command) && echo "succeed"; } || { echo "failed" && false; }
}
普段からこの形式で書くことはオススメはしないけど、ちょっとした時の tips として役に立つやも
背景
元々は「成功したら成功メッセージを書く」という処理を書いていたのだけど失敗した時の値を取りたいと思ったのがきっかけ。
# 元々のコード。ちょっとしたテストコード的なもの
assert() {
local cmd=$1
local expect=$2
local actual=$($cmd)
[[ "$actual" == *"$expect"* ]] && echo "succeed" >&2
}
このコードを、殆ど手直しすること無くデバッグ用のダンプを出そうとした結果
こうなった
# 変更後のコード。元のコードに殆ど手を加える必要がなかった事が勝因
assert() {
local cmd=$1
local expect=$2
local actual=$($cmd)
{ [[ "$actual" == *"$expect"* ]] && echo "succeed" >&2; } \
|| { echo "Actual: $actual" && false; }
}
true
コマンド、 false
コマンドを使ったシンプルなバージョンに落とし込むと何が起きているか分かりやすい。
$ { true && echo "true"; } || { echo "false" && false; }
true
$ echo $?
0
$ { false && echo "true"; } || { echo "false" && false; }
false
$ echo $?
1
true
の時はそのまま &&
演算子の右辺の echo "true"
が実行される。
この時どちらも成功ステータスなので { true && echo "true"; }
の結果は成功ステータス。
そうすると ||
演算子の挙動で右辺の評価はスキップされ、かつ成功ステータスが確定する。
ちなみに最初の値の結果によって右辺の評価をスキップする、この挙動を ショートサーキット評価 と呼ぶらしい
逆に false
の時は最初の &&
がショートサーキット評価により失敗ステータスで確定する。
なのでそのまま次の ||
演算子の右辺が評価される。今度は echo "false"
は成功するものの、そのまま右辺も評価され、 false
があることで失敗ステータスであることが確定する。
{}
を使ってグルーピングしているのは評価の順番を確実にしたかった為。(というか思ったように動いてくれなかったため←)
{}
のグルーピングはちゃんとセミコロン ;
で終わらせないと syntax error になるのも注意
ちなみに
echo 関数が失敗したらこちらの目論見は見事に失敗します。
まぁデバッグ用だし、echo コマンドがそうそう失敗するわけないよねと高をくくっている実装です。
つまりは
日々の利用にはオススメしません。
Author And Source
この問題について(`&&` と `||` のショートサーキット評価を利用したトリッキーな bash script の書き方), 我々は、より多くの情報をここで見つけました https://qiita.com/takayukioda/items/31b4dca6a2c2a11cbf47著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .