ネストされたループを持つシェルスクリプトがありますが、「exit」は実際にはスクリプトを終了せず、現在のループのみを終了することがわかりました。特定のエラー条件でスクリプトを完全に終了する別の方法はありますか?
許容可能なエラーがあり、多くの書き換えが必要になるため、「set -e」を使用したくありません。
現在、私はkillを使用して手動でプロセスをkillしていますが、これを行うにはもっと良い方法があるはずです。
ネストされたループを持つシェルスクリプトがありますが、「exit」は実際にはスクリプトを終了せず、現在のループのみを終了することがわかりました。特定のエラー条件でスクリプトを完全に終了する別の方法はありますか?
許容可能なエラーがあり、多くの書き換えが必要になるため、「set -e」を使用したくありません。
現在、私はkillを使用して手動でプロセスをkillしていますが、これを行うにはもっと良い方法があるはずです。
回答:
あなたの問題は、それ自体がループのネストではありません。1つ以上の内部ループがサブシェルで実行されているということです。
これは機能します:
#!/bin/bash
for i in $(seq 1 100); do
echo i $i
for j in $(seq 1 10) ; do
echo j $j
sleep 1
[[ $j = 3 ]] && { echo "I've had enough!" 1>&2; exit 1; }
done
echo "After the j loop."
done
echo "After all the loops."
出力:
i 1
j 1
j 2
j 3
I've had enough!
これはあなたが説明した問題を示しています:
#!/bin/bash
for i in $(seq 1 100); do
echo i $i
cat /etc/passwd | while read line; do
echo LINE $line
sleep 1
[[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
done
echo "After the j loop."
done
echo "After all the loops."
出力:
i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 2
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
After the j loop.
i 3
LINE root:x:0:0:root:/root:/bin/bash
(...etc...)
これが解決策です。サブシェルで実行される内部ループの戻り値をテストする必要があります。
#!/bin/bash
for i in $(seq 1 100); do
echo i $i
cat /etc/passwd | while read line; do
echo LINE $line
sleep 1
[[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
done
[[ $? != 0 ]] && exit $?
echo "After the j loop."
done
echo "After all the loops."
テストに注意してください: [[ $? != 0 ]] && exit $?
出力:
i 1
LINE root:x:0:0:root:/root:/bin/bash
LINE bin:x:1:1:bin:/bin:/sbin/nologin
LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
編集:現在のサブシェルを確認するには、「応答」スクリプトを変更して、現在のシェルのプロセスIDを通知します。注:これはbash 4でのみ機能します。
#!/bin/bash
for i in $(seq 1 100); do
echo pid $BASHPID i $i
cat /etc/passwd | while read line; do
echo pid $BASHPID LINE $line
sleep 1
[[ "$line" = "daemon:x:2:2:daemon:/sbin:/sbin/nologin" ]] && { echo "I've had enough!" 1>&2; exit 1; }
done
[[ $? != 0 ]] && echo pid $BASHPID && exit $?
echo "After the j loop."
done
echo "After all the loops."
出力:
pid 31793 i 1
pid 31796 LINE root:x:0:0:root:/root:/bin/bash
pid 31796 LINE bin:x:1:1:bin:/bin:/sbin/nologin
pid 31796 LINE daemon:x:2:2:daemon:/sbin:/sbin/nologin
I've had enough!
pid 31793
変数「i」と「j」は、Fortranの好意により提供されました。ごきげんよう。:-)
bash --version
には、コマンドラインに入力します。
以前の答えは、使用することを提案している[[ $? != 0 ]] && exit $?
が、この意志はない、非常に期待されるようので、仕事を[[ $? != 0 ]]
テストがリセットされ$?
ている手段スクリプトが早期終了します予想通りものの、それは(期待できないとして)コード0で常に終了だろうと、ゼロに戻って。また、文字列比較テスト-ne
ではなく、数値比較テストを使用することをお勧めします!=
。したがって、私見のより良い解決策は以下を使用することです:
err=$?; [[ $err -ne 0 ]] && exit $err
実際の終了コードが正しく設定されていることを確認するためです。
使用できますbreak
。
からhelp break
:
Exit a FOR, WHILE or UNTIL loop. If N is specified, break N enclosing loops.
したがって、3つの囲んでいるループを終了するには、メインのループ内に2つのネストされたループがある場合、これを使用してすべてのループを終了します。
break 3
for((i=0;i<3;i++));do echo A;for((j=0;j<2;j++));do echo B;break 2;done;done
bash -c 'for x in y z; do exit; done; echo "This never gets printed"'
。