while
Bashループの「条件」セクションで繰り返し呼び出される関数の終了コードを取得しようとしています。
while <function>; do
<stuff>
done
エラーのためにこのループが終了したときに必要な終了コード<function>
。それを得る方法についてのアイデアはありますか?
答え1
条件の終了値をキャプチャして前方に伝播できます。
while rmdir FOO; ss=$?; [[ $ss -eq 0 ]]
do
echo in loop
done
echo "out of loop with ?=$? but ss=$ss"
出力
rmdir: failed to remove 'FOO': No such file or directory
out of loop with ?=0 but ss=1
この場合、終了ステータスはrmdir FOO
変数にキャプチャされていss
ます1
。 (rmdir FOO
に置き換えてください( exit 4 )
。と表示されますss=4
。)
どのように動作しますか?構文は実際にはよりwhile list-1; do list-2; done
一般的な期待ではないことに注意してくださいwhile command; do list; done
。セミコロンで区切られた一連の命令であり、マニュアルにlist-1
はwhile
list-2
このコマンドは、リストの最後のコマンドが終了ステータス0を返す限り、リストを実行し続けますlist-1
。」
混乱しているように見えるwhile
条件を表現する別の方法として、式の内部に変数を割り当てた(( ... ))
後、その結果を使用できます。これは読みにくいですが、より簡潔な割り当てとテスト構造を提供します。
while rmdir FOO; ((! (ss=$?)))
do
echo in loop
done
echo "out of loop with ?=$? but ss=$ss"
またはを使用できますwhile rmdir FOO; ! (( ss=$? ))
。これは、((1)の算術評価が1であり、通常はtrueに関連付けられ、その評価の終了コードが0(成功)であるために機能します。一方、((0))の算術評価は0であり、これは通常falseに関連付けられているため、この計算の終了コードは1(失敗)です。両方の評価が「成功」した後に混乱しているように見えるかもしれませんが、bashの成功/失敗終了コードと一致するtrue / falseを表す算術式の値を作成し、などの条件式に基づいているかどうかに関係なく作成する((.))
ことはハッキングですです。終了コードや算術値はすべてうまく機能します。if ...; then ...; fi
while ...; do ...; done
答え2
これを達成する1つの方法は、テストを委任するのではなく明示的に作成することですwhile
。したがって、次のことを行う必要があります。
err=0
while true
do
<function>
(( (err=$?) > 0 )) && break
<stuff>
done
echo "$err"
(先験的無限)ループの先頭で条件付きコマンドを「手動で」実行し、終了コードを保存して確認し、ゼロでない場合(失敗を示す)ループを終了します。 0の場合にのみ「実際の」ループコードを実行します。
@roaimaが指摘したように、(( ... ))
算術テスト構成内で変数割り当てを実行できるため、構文を「圧縮」できます。
答え3
関数の終了コードの結果として変数を設定するラッパー関数を作成します。例:
e=0
# file does not exist
foo() {
rm xyz
}
baz() {
foo
e=$?
[[ $e -ne 0 ]] && return 1
return 0
}
# create a file
touch xyz
while baz; do
# first loop succeeds, the file exists
# second loop exits with error, file doesn't exists
echo in loop
done
in loop
rm: cannot remove 'xyz': No such file or directory
# then
$ echo $e
1
答え4
を使用すると、匿名関数で使用zsh
できます。return
() while ((1)) {
<function> || return
<stuff>
}
print $?
Bourneに似たシェルでは、いつでも名前付き関数を使用できます。
repeat_until_fail()
while true; do
<function> || return
<stuff>
done
repeat_until_fail
echo "$?"