【Shell Script】for文・whileループで繰り返し処理をする

Shell Script

こんにちは、かつコーチです。

「同じコマンドを10回コピペして実行している」「ファイルを1つずつ手作業で処理している」。
そんな作業に心当たりがあるなら、ループを覚えるタイミングです。
この記事では、シェルスクリプトの繰り返し処理の基本であるfor文とwhileループの使い方を、初心者向けに解説します。
if文(04-if-bun-joken-bunki)と組み合わせれば、実務でよく使う「複数ファイルを一括処理する」スクリプトが書けるようになります。

ループとは?

同じ処理を繰り返す仕組み

ループとは、指定した条件を満たしている間、同じ処理を繰り返し実行する仕組みです。

たとえるなら、宅配ドライバーが配達リストを1件ずつ回っていく作業に似ています。
配達先が10件あれば、ドライバーは同じ「訪問して荷物を渡す」という作業を10回繰り返します。
リストの件数分だけ処理を繰り返すのがfor文、条件を満たす間は回り続けるのがwhileループとイメージすると理解しやすいです。

なぜループが必要なのか

シェルスクリプトを使う目的の多くは「定型作業の自動化」です。
ファイルを1つずつ処理する、行を1行ずつ読み込む、といった作業を手作業で繰り返すのは非効率ですし、件数が多いとミスも起こります。
ループを使えば、処理内容を1回書くだけで、対象がいくつあっても同じ精度で処理を回せます。

基本の書き方

for文:リストを1つずつ処理する

for文は、リストの要素を先頭から順に変数へ入れながら処理を繰り返します。

#!/bin/bash

for i in 1 2 3
do
  echo "$i番目の処理です"
done

連番を作るときは{1..10}seqが便利です。

#!/bin/bash

# 1から5までの連番でループする
for i in {1..5}
do
  echo "カウント: $i"
done

実務でよく使うのは、ファイル一覧をループで処理するパターンです。

#!/bin/bash

# カレントディレクトリの.txtファイルを1つずつ表示する
for file in *.txt
do
  echo "対象ファイル: $file"
done

whileループ:条件を満たす間繰り返す

whileループは、条件式が真である間、処理を繰り返します。

#!/bin/bash

count=1

while [ "$count" -le 5 ]
do
  echo "カウント: $count"
  count=$((count + 1))
done

count=$((count + 1))でカウンターを1つずつ増やし、[ "$count" -le 5 ]が偽になった時点でループを抜けます。
カウンターを更新し忘れると条件が永遠に真のままになり、無限ループになるので注意してください。

ファイルを1行ずつ読み込むwhileループ

whileループは、ファイルの中身を1行ずつ処理する用途でもよく使われます。

#!/bin/bash

while read -r line
do
  echo "読み込んだ行: $line"
done < list.txt

read -rが1行読み込むたびに真を返すので、ファイルの最終行まで自動的に繰り返されます。

よくあるつまずきポイント・エラー対処

パイプで渡したwhileループの中で変数が消える

ファイルの行数を数えながら処理しようとして、次のように書いたことがあります。

❌Before(つまずいた実例)

#!/bin/bash

count=0

cat list.txt | while read -r line
do
  count=$((count + 1))
done

echo "処理件数: $count"

ループの中では正しくカウントされているはずなのに、実行すると必ず処理件数: 0と表示されて困惑しました。

✅After(解決方法)

原因は、パイプ(|)でつないだ右側のwhileループがサブシェルという別プロセスで実行されるためです。
サブシェルの中で更新したcountは、元のシェルには反映されません。
< list.txtでファイルを直接whileに渡す形に書き換えたところ、サブシェルが発生せず正しくカウントできました。

#!/bin/bash

count=0

while read -r line
do
  count=$((count + 1))
done < list.txt

echo "処理件数: $count"

「パイプでつなぐと別プロセスになる」という仕組みを知らないと、原因の見当がつかず時間を浪費してしまうポイントです。

応用・一歩先の使い方

breakとcontinueでループ制御する

ループの途中で処理を止めたい、あるいは特定の条件だけスキップしたい場合はbreakcontinueを使います。

#!/bin/bash

for i in {1..10}
do
  if [ "$i" -eq 5 ]; then
    break  # 5になったらループを終了
  fi
  if [ $((i % 2)) -eq 0 ]; then
    continue  # 偶数はスキップして次のループへ
  fi
  echo "奇数: $i"
done

C言語風のfor文

条件式・更新式を自分で書きたい場合は、C言語のような書き方も使えます。

#!/bin/bash

for ((i = 0; i < 5; i++))
do
  echo "index: $i"
done

数値の増減で細かく制御したいときに便利ですが、リストの単純な繰り返しであれば通常のfor文の方が読みやすい場合が多いです。

まとめ

この記事のポイント

  • for文はリストの要素を順に処理し、whileループは条件が真の間処理を繰り返す
  • ファイルを1行ずつ処理するならwhile read -r line; do ... done < fileの形が基本
  • パイプでwhileにつなぐとサブシェルになり、ループ内の変数変更が外に反映されない
  • breakでループを中断、continueで次のループへスキップできる

次に読むべき記事

繰り返し処理の次は、複数条件をすっきり書ける「case文で複数条件をすっきり書く」を読んでみてください。

タグ: Shell, 初心者向け, 制御構文

タイトルとURLをコピーしました