ループのショートカット

ループのショートカット

ショートカット:、ステートメントの(expr1 && expr2)代わりに。if ... fiループを介して、...を生成したい場合はできますかexpr1expr2

おもちゃの例は次のとおりです。

$ for cond in {0,0,0}; do if [[ $cond = 0 ]]; then echo 0; else echo 1; break; fi; done && echo "true" || echo "false"
0
0
0
true

$ for cond in {0,1,0}; do if [[ $cond = 0 ]]; then echo 0; else echo 1; break; fi; done && echo "true" || echo "false"
0
1
true

最初の文だけを返し、2番目の文は返すようにif...fiこの文をどのように変更できますか?内部に交換すると、ターミナルウィンドウが閉じます。truefalseecho 1exit

答え1

ループの終了状態は、ループ内で実行された最後のコマンドの終了状態(echoまたは)breakであり、両方の終了状態は通常ゼロです。したがって、条件を保存して状態を確認する必要があります。次の機能を使用することをお勧めします。

loopcheck() {
for cond in {0,1,0}; do
  if [[ $cond = 0 ]]; then
    echo 0; 
  else
    ret=$?;   # preserve exit status of test
    echo 1; 
    return $ret;  # pass it on
  fi;
done
}

loopcheck && echo "true" || echo "false"

別のオプションは、$ret上記のように保存し、ループの外側でその値をチェックすることです。

答え2

私は取るこれ質問に示されている内容に近いので、他の答えよりも優れています(有用ですが)。

$ (for cond in {0,1,0}; do if [[ $cond = 0 ]]; then true; else false; exit; fi; done) && echo "true" || echo "false" false 

答え3

ループリレーfor name in ...の最後の実行コマンドの終了状態です。

breakループを実行すると、break コマンド自体の終了状態がデフォルトでゼロであるため、中継されるため、以降のテストは同じになりますfor&&donetrue

この問題を解決する1つの方法は、独自の答えで述べたとおりです。これは素晴らしい、きれいなシェルであり、すべてのPOSIX互換シェルでうまく機能します。

しかし、サブシェルとして機能を完全に共有しないため、欠点があります。実行環境1とその「外部」シェル。実行が開始されるとそれを継承しますが、実行が完了すると「外部」親に再び「伝播」しません。つまり、たとえば、ループ内で設定または変更されたすべての変数は、後でループの外にはありません。より。

Bashには代替手段があります。サブシェルの使用を避け、引き続き使用できますが、終了するループの数が常に無効であるため、引数を渡してbreak失敗するように強制できます。 Bashはエラーメッセージを表示しますが、リダイレクトしてそれを無音に設定できます。-1-12>/dev/null

ただし、この動作はPOSIXと完全に互換性がないと見なされますbreak特殊内蔵、そしてエラーを発生させる「特殊組み込み」出なければならない非対話型シェル(例:スクリプト)。

1[… ]。変更サブシェル環境は影響を受けません。シェル実行環境。 [...]

関連情報