閉じる

Bashの繰り返し処理:forとwhileの使い分けと実践的な書き方

Bashスクリプトにおいて、同じ作業を何度も繰り返す処理は、自動化の核心とも言える重要な要素です。

大量のファイルを一括でリネームしたり、ログファイルの内容を一行ずつ解析したりする際、繰り返し処理(ループ)を適切に使いこなすことで、手作業によるミスを排除し、業務効率を劇的に向上させることができます。

Bashには主に「for文」と「while文」という2つの強力な繰り返し構文が用意されていますが、これらを状況に応じて正しく使い分けることが、保守性の高いスクリプトを書くための第一歩となります。

本記事では、2026年現在のシステム運用でも標準的に利用されているBashのループ処理について、基礎から実践的な応用テクニックまで詳しく解説します。

Bashにおける繰り返し処理の基本概念

Bashスクリプトで利用されるループ処理には、大きく分けて「回数や対象が明確な処理」と「条件が満たされている間継続する処理」の2パターンが存在します。

一般的に、あらかじめ処理対象のリストが決まっている場合はfor文を使用し、特定の条件が変化するまで処理を続けたい場合にはwhile文を選択します。

この使い分けを誤ると、無限ループに陥ってシステムリソースを浪費したり、予期せぬ挙動によってデータを破損させたりするリスクがあるため注意が必要です。

現代のシェルスクリプト開発では、単に動くだけでなく、読みやすさとエラーに対する強さ(堅牢性)が強く求められます。

for文の基本とバリエーション

for文は、指定したリストに含まれる要素の数だけ処理を繰り返すための構文です。

最も基本的な使い方は、スペース区切りの文字列や配列の要素を順番に変数へ代入して実行する形式です。

基本的なリスト形式のfor文

まずは、特定の単語リストを順番に処理する最もシンプルな例を見てみましょう。

Shell
#!/bin/bash

# 果物の名前を順番に表示する
for fruit in apple banana cherry
do
    echo "I like $fruit"
done
実行結果
I like apple
I like banana
I like cherry

この形式では、inの後に記述された要素が1つずつ変数fruitに格納され、doからdoneまでのブロックが実行されます。

ブレース展開を利用した数値指定ループ

特定の回数だけ処理を繰り返したい場合、Bashのブレース展開を利用するのが効率的です。

Shell
#!/bin/bash

# 1から5までの数字を順番に出力する
for i in {1..5}
do
    echo "Count: $i"
done
実行結果
Count: 1
Count: 2
Count: 3
Count: 4
Count: 5

{開始..終了}という記述により、連続した数値を自動生成してループに渡すことができます。

さらに、{1..10..2}のように記述することで、1, 3, 5…といった「ステップ指定」のループも可能です。

C言語スタイルのfor文

Bashでは、他のプログラミング言語(C言語やJavaなど)に馴染みがあるエンジニアにとって扱いやすい、3つの式を用いた算術的なfor文も利用可能です。

Shell
#!/bin/bash

# C言語スタイルのforループ
for ((i=0; i<5; i++))
do
    echo "Number: $i"
done
実行結果
Number: 0
Number: 1
Number: 2
Number: 3
Number: 4

この形式は、ループ変数の増分を細かく制御したい場合や、複雑な計算条件を伴う場合に非常に便利です。

ただし、Bash特有の書き方であるため、POSIX準拠(sh)のスクリプトでは動作しない点に留意してください。

while文による条件ベースの繰り返し

while文は、指定した条件式が真(true)である限り、処理を永続的に繰り返す構文です。

処理の回数が事前に決まっていない場合や、外部の状態変化を待機する場合に適しています。

数値比較によるwhileループ

変数の値を変化させながら、特定の条件を満たさなくなるまで繰り返す例です。

Shell
#!/bin/bash

counter=1

# カウンターが5以下の間繰り返す
while [ $counter -le 5 ]
do
    echo "Counter: $counter"
    # カウンターを1増やす
    ((counter++))
done
実行結果
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5

ここで重要なのは、ループ内で必ず条件式を偽(false)にするための処理を含めることです。

上記の例では ((counter++)) を忘れると、永遠に1を表示し続ける「無限ループ」が発生してしまいます。

無限ループの作成と活用

意図的に無限ループを作成し、その中で特定の条件を判定して終了させるパターンもよく使われます。

サーバーの稼働監視や、ユーザーからの入力を待ち続けるデーモンプログラムのような処理に最適です。

Shell
#!/bin/bash

while true
do
    echo "Processing..."
    sleep 2 # 2秒待機
    
    # 実際にはここで何らかのチェックを行い、breakで抜ける
done

無限ループを作成した際は、必ずCtrl+Cで停止させるか、適切な終了条件(break)を設定してください。

実践的なテクニック:ファイルとデータの処理

実際の業務において、for文とwhile文が最も威力を発揮するのは、ファイル操作やテキストデータの加工です。

ワイルドカードを用いたファイル一覧の処理

特定のディレクトリ内にある全てのファイルを対象に処理を行う場合、for文とワイルドカードを組み合わせます。

Shell
#!/bin/bash

# カレントディレクトリの.logファイルを全てバックアップする
for log_file in *.log
do
    # ファイルが存在しない場合の考慮
    [ -e "$log_file" ] || continue
    
    cp "$log_file" "${log_file}.bak"
    echo "Backed up: $log_file"
done

この方法では、スペースを含むファイル名も比較的安全に扱うことができます。

while read文によるテキストファイルの1行読み込み

テキストファイルの内容を一行ずつ処理する場合、Bashではwhile read構文が推奨されます。

for文でファイルの中身を読み込もうとすると、スペースや改行の扱いで予期せぬ分割が発生しやすいため、ファイル読み込みにはwhile文を使うのが鉄則です。

Shell
#!/bin/bash

file_path="user_list.txt"

# ファイルを一行ずつ読み込んで変数lineに格納する
while IFS= read -r line
do
    echo "Processing user: $line"
done < "$file_path"

IFS= は行頭や行末の空白を保持するための設定であり、-r オプションはバックスラッシュをエスケープ文字として解釈しないようにするための重要な指定です。

この書き方は、大量のログ解析や設定ファイルの読み込みにおいて、非常に高い信頼性を発揮します。

ループの制御:breakとcontinue

繰り返し処理の途中で、特定の条件に基づいてループ全体を終了させたり、現在のステップをスキップしたりすることができます。

breakによるループの脱出

breakを使用すると、ループの条件がまだ真であっても、強制的に繰り返し処理を終了します。

Shell
#!/bin/bash

for num in {1..10}
do
    if [ $num -eq 6 ]; then
        echo "Found 6, breaking loop."
        break
    fi
    echo "Number: $num"
done

continueによるステップのスキップ

continueを使用すると、それ以降の処理を飛ばして、次の繰り返しの先頭に戻ります。

Shell
#!/bin/bash

for num in {1..5}
do
    if [ $num -eq 3 ]; then
        # 3の時だけスキップ
        continue
    fi
    echo "Number: $num"
done

for文とwhile文の使い分け比較

どちらを使うべきか迷った際のために、それぞれの特徴を表にまとめました。

項目for文while文
主な用途個数や範囲が決まっている処理条件が満たされている間の継続処理
典型的な対象配列、ファイルリスト、数値範囲ファイル行読み込み、監視、フラグ判定
書きやすさシンプルで簡潔柔軟だが無限ループのケアが必要
得意な場面ディレクトリ内の全ファイル操作外部コマンドの結果を逐次処理

基本的には、「対象物が最初から見えているならfor、条件が変わるのを待つならwhile」と覚えるとスムーズに使いこなせます。

ループ処理のパフォーマンスと注意点

シェルスクリプトのループ処理は、他のコンパイル言語と比較すると実行速度が遅くなる傾向があります。

特に、数万行を超えるような巨大なファイルをwhile文で一行ずつ読み込む処理は、数分かかる場合もあります。

このような場合、可能であれば sedawk などの外部コマンドを活用して、一括で処理することを検討してください。

また、ループ内で外部コマンド(grepcutなど)を呼び出すと、そのたびに新しいプロセスが生成されるため、大きな負荷となります。

Bashの組み込み変数展開機能を活用し、極力シェル内部で完結させる書き方を意識することが、高速なスクリプトへの近道です。

トラブルシューティング:よくあるミス

繰り返し処理を書く際、初心者が陥りやすいミスがいくつかあります。

一つ目は、変数のクォート忘れです。

ファイル名にスペースが含まれている場合、"$file"のようにダブルクォートで囲まないと、ループが正しく機能しません。

二つ目は、パイプを使用した際の「サブシェル問題」です。

cat file | while read line のように記述すると、while文がサブシェルで実行されるため、ループ内で変更した変数がループ外で保持されません。

この問題を回避するには、前述した done < file のリダイレクト形式を使用することを強く推奨します。

まとめ

Bashの繰り返し処理であるfor文とwhile文は、システム自動化の根幹を支える非常に重要なツールです。

for文はリストや範囲が決まっている場合に威力を発揮し、直感的に記述できるメリットがあります。

一方でwhile文は、条件に基づいた柔軟な制御が可能であり、特にファイル読み込みにおいて欠かせない存在です。

それぞれの特性を理解し、クォートの適切な使用やリダイレクトの活用といった基本を忠実に守ることで、安全で効率的なスクリプトを構築することができます。

まずは小さな自動化から始め、今回学んだ繰り返し処理を積極的に取り入れてみてください。

URLをコピーしました!