Bash のbreakとcontinue文
break および continue 文は、Bashスクリプト内のループプロセスの制御において非常に強力なメカニズムを提供します。これらを使用することで、特定の条件に基づいてループの通常の実行軌道を変更し、スクリプトをより効率的かつ柔軟に構築できます。
1. break と continue の理解
break と continue はどちらも制御フロー文であり、特にループ構造(for、while、until など)の内部で使用され、コードの実行方法を修正するために用いられます。
1.1 break 文
break 文の役割は、現在のループを終了し、プログラムの制御をループ本体の直後にある次の文に移すことです。これをループの「緊急出口」と考えることができます。コードの実行が break に達すると、ループ自体の条件が依然として満たされていても、ループは即座に停止します。
コード例:
#!/bin/bash
for i in {1..10}
do
if [ $i -gt 5 ]; then
echo "i = $i の時にループを中断 (Breaking the loop)"
break # ループを抜ける
fi
echo "i = $i"
done
echo "ループ終了。"この例では、ループは本来 1 から 10 までイテレートする予定でした。しかし、i の値が 5 より大きくなった時に break 文が実行され、ループは途中で終了します。
出力結果:
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6 の時にループを中断 (Breaking the loop)
ループ終了。原理の解析: スクリプトは 1 から 10 までの数値を走査します。i が 6 になった時、条件 $i -gt 5 が真(true)と判定されます。その後、break 文がトリガーされ、ループが即座に終了します。続いて、スクリプトはループ本体の外部にある次の行を実行し、「ループ終了。」と出力します。
1.2 continue 文
continue 文の役割は、現在のループイテレーションの残りの部分をスキップし、直接次のイテレーションに進むことです。これは現在のサイクル内の continue 以降のコマンドを実行せずに、ループの次の周期に直接ジャンプすることを意味します。
コード例:
#!/bin/bash
for i in {1..10}
do
if [ $((i % 2)) -eq 0 ]; then
continue # 偶数をスキップ
fi
echo "i = $i"
done
echo "ループ終了。"この例では、ループは 1 から 10 までイテレートします。i が偶数の時、continue 文が実行され、そのイテレーション内の echo コマンドがスキップされます。
出力結果:
i = 1
i = 3
i = 5
i = 7
i = 9
ループ終了。原理の解析: スクリプトは 1 から 10 までの数値を走査します。各偶数に対して、条件 $((i % 2)) -eq 0 が真になります。continue 文が実行されると、現在のイテレーションの残りの部分(すなわち echo コマンド)がスキップされます。その後、スクリプトは直接ループの次の数値へと進み、イテレーションを継続します。
2. ネストされたループとラベル
デフォルトでは、break と continue はそれらが記述されている最も内側のループにのみ影響します。内側のループから外側のループの動作を制御したい場合は、ラベル(labels)を使用する必要があります。
2.1 ラベル付きの break
コード例:
#!/bin/bash
outer_loop: for i in {1..3}
do
echo "外側のループ i = $i"
for j in {1..3}
do
echo " 内側のループ j = $j"
if [ $i -eq 2 ] && [ $j -eq 2 ]; then
echo " 外側のループを中断!"
break outer_loop # outer_loop ラベルが付いた外側のループを直接抜ける
fi
done
done
echo "ループ終了。"出力結果:
外側のループ i = 1
内側のループ j = 1
内側のループ j = 2
内側のループ j = 3
外側のループ i = 2
内側のループ j = 1
内側のループ j = 2
外側のループを中断!
ループ終了。原理の解析: この例は、内側のループ内の特定の条件が満たされた時に、どのようにして特定の(外側の)ループを直接抜けるかを示しています。outer_loop: ラベルは外側のループを識別します。その後の break outer_loop コマンドは、正確にそのマークされたループの階層から脱出します。
2.2 ラベル付きの continue
(注意:この使い方は比較的稀ですが、完全に有効です)
コード例:
#!/bin/bash
outer_loop: for i in {1..5}
do
for j in {1..3}
do
if [ $j -eq 2 ]; then
continue outer_loop # 外側のループの残りの部分をスキップし、外側のループの次のイテレーションへ進む
fi
echo "i=$i, j=$j"
done
echo "外側のループ i=$i のイテレーション終了"
done出力結果:
i=1, j=1
i=3, j=1
i=4, j=1
i=5, j=1原理の解析: continue outer_loop 文は現在の外側ループイテレーションの残りの内容をスキップし、直接次の i 値へとジャンプします。そのため、「外側のループイテレーション終了」というメッセージや j=3 の時のメッセージはすべてスキップされます。なぜなら外側のループが即座に再起動(次のサイクルへ移行)されたからです。
3. 実践的なユースケースのデモンストレーション
3.1 ディレクトリ内の特定ファイルをスキップする
多様なファイルが含まれるディレクトリがあり、.txt ファイルのみを処理し、すべての .log ログファイルをスキップしたいと仮定します。
#!/bin/bash
for file in *
do
if [[ "$file" == *.log ]]; then
echo "ログファイルをスキップ: $file"
continue # .log ファイルをスキップ
fi
echo "ファイルを処理中: $file"
# ここにファイル処理のロジックを追加
doneこの例では、ループがカレントディレクトリ下のすべてのファイルを走査します。ファイル名が .log で終わる場合、continue 文がループ本体の残りの部分をスキップし、直接次のファイルを確認しに行きます。
3.2 特定のエラー発生時にループを終了する
ファイルを 1 行ずつ読み込み、無効なフォーマットの行に遭遇した時に処理を停止したいと仮定します。
#!/bin/bash
while IFS= read -r line
do
if [[ ! "$line" =~ ^[0-9]+,[A-Za-z]+$ ]]; then
echo "無効なフォーマットに遭遇: $line"
break # フォーマットが無効な場合、ループを終了
fi
# 行データを処理(フォーマットが正しいことが前提)
echo "行を処理中: $line"
done < data.txtここでは、ループが data.txt から各行を読み取ります。ある行のデータが期待されるフォーマット(例:数値、コンマ、アルファベット)に適合しない場合、break 文がループ全体を終了させます。
もし data.txt に以下の内容が含まれている場合:
123,Valid
456,AnotherValid
Invalid Data
789,StillValid出力結果は次のようになります:
行を処理中: 123,Valid
行を処理中: 456,AnotherValid
無効なフォーマットに遭遇: Invalid Data3.3 break を使用したシンプルなメニューの実装
この例では、メニュー画面を表す無限の while ループを break で終了させます。
#!/bin/bash
while true; do
echo "メニュー:"
echo "1. オプション 1"
echo "2. オプション 2"
echo "3. 終了"
read -p "選択肢を入力してください: " choice
case $choice in
1)
echo "オプション 1 を実行中"
;;
2)
echo "オプション 2 を実行中"
;;
3)
echo "終了中..."
break # ループを抜ける
;;
*)
echo "無効な選択です。再試行してください。"
;;
esac
done
echo "プログラム実行終了。"この例では、while true ループはユーザーが '3' を入力するまで無限に実行されます。'3' が入力されると break 文がトリガーされ、ループが終了します。
3.4 continue を使用した特定範囲の数値フィルタリング
1 から 20 までの数値を出力しますが、3 の倍数をスキップするデモンストレーションです。
#!/bin/bash
for i in $(seq 1 20); do
if [[ $((i % 3)) -eq 0 ]]; then
continue # 3 の倍数をスキップ
fi
echo "$i"
doneこのスクリプトは 1 から 20 までの数値を出力しますが、3, 6, 9, 12, 15, 18 は除外されます。