Bash "while"ループが終了すると、条件付き関数の終了コードが必要です。

Bash "while"ループが終了すると、条件付き関数の終了コードが必要です。

whileBashループの「条件」セクションで繰り返し呼び出される関数の終了コードを取得しようとしています。

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-1whilelist-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 ...; fiwhile ...; 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 "$?"

関連情報