一連のジョブを実行し、そのうちの1つでも失敗した場合は停止したかったので、次のように書きました。
for task in [TASKS]; do
process "$task" || break
commit "$task"
done
これはうまくいきますが(例:指定済み) 早く中断してもループの終了状態はゼロです。理想的には、break
-ingは失敗を伝えることができます。
0
リターンが文書化された動作であることを知っていますが、break
比較的きれいな回避策があるかどうか疑問に思います。私が想像できる最善の方法は、それを関数で囲んでdidBreak
変数を設定し、それを(関数の)終了状態として使用することです。うまくいきますが、複雑すぎると感じます。
答え1
これは多くのシェルで使用できます! break
(pdkshベースのシェルとsh
FreeBSDシェルを除く(渡す デザイン)私のテストから):
$ zsh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ bash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ ksh88 -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ ksh93 -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ dash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ yash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ bosh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ pdksh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
$ mksh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
$ posh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
errexit
どちらも実行されません。
それaustin-group(POSIXの背後にある機関)メーリングリストについて話し合ってください。昨年。 (bosh
FreeBSDsh
とNetBSDマネージャを含む)議論はsh
合意に達する前に終わりましたが、一般的な見解では、POSIXは!
コマンドの終了状態を否定することによって文書化されているようにこの動作を要求しました。break
これはコマンドの終了ステータスを否定する特別な組み込みコマンドです。でした。 0 終了状態で終了します。
しかし、例えば、同じ推論を適用すると、return
声明に合うシェルが少ないことがわかります。
では、代わりに匿名関数をzsh
使用できます。return
break
$ () for i in x y; do echo $i; return 1; done
x
$ echo $?
1
答え2
次のようなことができます
failed=false
for task in "${tasks[@]}"; do
if ! process "$task"; then
failed=true
break
fi
commit "$task"
done
if "$failed"; then
echo "Failed something" >&2
fi
答え3
私が想像する解決策は次のとおりです。
run_til_failure() {
local didBreak=0
for task in [TASKS]; do
process "$task" || { didBreak=1; break; }
commit "$task"
done
local loopExit=$?
if (( loopExit )); then return $loopExit; fi
return $didBreak
}