🐧 Linux 総合学習プラットフォーム
シェルスクリプト ・ 中級

繰り返し(for / while)

同じ処理を何度も行うには繰り返し(ループ)を使います。for は決まったリストを1つずつ処理するのに向き、for f in *.txt; do ... done のようにファイル群へまとめて処理できます。while は条件が真である間ずっと繰り返し、while read line; do ... done < file のように1行ずつ読む用途で活躍します。途中で抜けるには break、次の周回へ飛ばすには continue を使います。

繰り返し(ループ)は、同じような処理を何度も自動でこなすための仕組みだ。

同じ処理を100個のファイルに施したいとき、コマンドを100行コピーして並べるのは現実的でない。ループを使えば、これが数行で書ける。

💡
ポイントループは、同じ処理を何度も自動でこなす仕組み。100個のファイルへの処理も、コピペでなく数行で書ける。

たくさんのファイルに同じ加工をする、決まった回数だけ処理を回す、ファイルを1行ずつ読んで順に処理する、こうした作業はループの得意分野だ。

bash の代表的なループは for と while の2つで、それぞれ得意とする場面が違う。両者の性格を理解して使い分けられると、スクリプトで自動化できる仕事の幅が大きく広がる。まずは「決まったリストを回す for」から見ていこう。

🔁 for は1つずつ取り出す

for は「あらかじめ決まったリストの要素を、先頭から1つずつ取り出して繰り返す」のに向いたループだ。基本形は for 変数 in リスト; do 処理; done で、in の後ろに並べた値を変数に順に入れながら、do から done までを繰り返す。

for fruit in りんご みかん ぶどう; do … doneりんごみかんぶどう順に処理$fruit に1つずつ入れながら do〜done を繰り返す

たとえば for fruit in りんご みかん ぶどう; do echo "果物: $fruit"; done と書くと、3つの果物を順に表示する。

実務で特に強力なのが、ファイル名のパターン(ワイルドカード)と組み合わせる使い方だ。for f in *.txt; do echo "$f"; done とすれば、カレントディレクトリにある拡張子 .txt のファイルすべてに対して、まとめて同じ処理を施せる。冒頭の「100個のファイル」も、これなら数行で片づく。

for f in *.txt; do echo "$f"; done ……拡張子 .txt のファイルすべてに、まとめて同じ処理を施せる。

連続した数値を回したいときは seq コマンドが便利で、for i in $(seq 1 5); do echo "回数 $i"; done のようにコマンド置換と組み合わせれば、1から5までの繰り返しになる。bash には for ((i=1; i<=5; i++)); do ... done という、C言語に似た数え上げの書き方もある。

⏳ 回数が決まっていないときは while

リストの長さがあらかじめ分からない、条件が満たされる間だけ回したい、そんなときに使うのが while だ。while は「指定した条件が成り立つ(真である)間、ずっと繰り返す」ループだ。

💡
ポイントfor は決まったリストを1つずつ、while は条件が成り立つ間ずっと。回数が読めないときは while を選ぶ。

基本形は while 条件; do 処理; done で、繰り返すたびに条件を確かめ、成り立たなくなった時点でループを抜ける。条件の判定には、if 文と同じく [ ] や test を使う。前章の条件分岐の知識が、そのままループの制御に流用できるわけだ。

カウンタを使った例を見ると動きが分かりやすい。i=1; while [ "$i" -le 3 ]; do echo "i は $i"; i=$((i + 1)); done と書くと、i が3以下である間だけ繰り返し、i は1、2、3と表示される。

i=1; while [ "$i" -le 3 ]; do echo "i は $i"; i=$((i + 1)); done ……i が3以下の間だけ回り、1、2、3 と表示される。

ここで i=$((i + 1)) は算術展開 $(( )) を使ってカウンタを1増やす処理だ。while で繰り返しの回数を制御するときは、このようにループの中で必ずカウンタを更新する必要がある。

📄 ファイルを1行ずつ読む

while が真価を発揮するのが、ファイルやコマンド出力を1行ずつ処理する場面だ。while read line; do 処理; done < file という形が定番で、ファイルの内容を上から1行ずつ変数 line に読み込みながら繰り返す。

while read line; do … done < file ……ファイルの中身を上から1行ずつ変数 line に読み込みながら繰り返す。

末尾の < file はリダイレクトで、file の中身をループの標準入力として流し込んでいる。たとえば設定ファイルを1行ずつ点検したり、リスト化されたサーバ名を順に処理したりするのに使う。

これで最後まで読み切れて、しかも止まる理由はこうだ。read は読み込む行が無くなると失敗(終了ステータス0以外)を返すので、ファイルの最後まで来ると自然にループが終わる。

コマンドの出力を1行ずつ処理したいときは、ファイルの代わりにパイプを使って somecommand | while read line; do ...; done と書くこともできる。

⤵ 途中で抜ける、1回だけ飛ばす

ループの途中で繰り返しを打ち切ったり、一部の周回だけ飛ばしたりしたいときは、break と continue を使う。

break は、その時点でループ全体を即座に抜ける。たとえば探していた値が見つかった瞬間に、それ以上回す必要がなければ break で抜ける、という使い方をする。

breakループ全体を即座に抜ける停止→ もう回らないcontinue今の周回だけ飛ばし、次へ進む飛ばす

一方 continue は、現在の周回の残りの処理をスキップして、すぐ次の周回へ進む。条件に合わない要素だけ処理を飛ばして次へ行きたいときに便利だ。

コツbreak はループ全体を抜ける、continue は今の周回だけ飛ばして次へ進む。打ち切りか、1回スキップかで使い分ける。

たとえば for f in *.txt; do if [ ! -s "$f" ]; then continue; fi; echo "$f を処理"; done と書けば、中身が空のファイル(-s は「サイズが0より大きい」を意味し、! で否定)は処理をスキップし、中身のあるファイルだけを処理できる。

🛑 止まらなくなったら、どうする

ループで最も気を付けたいのが無限ループだ。while ループでカウンタの更新を書き忘れると、条件がいつまでも真のままになり、繰り返しが永遠に止まらない。

先ほどの例で i=$((i + 1)) を書き忘れると、i はずっと1のままなので i は1が延々と表示され続ける。もしこの状態に陥ってしまったら、Ctrl + c を押せば実行中のループを強制的に止められる。覚えておくと、いざというとき慌てずに済む。

つまずきwhile でカウンタの更新を忘れると無限ループになる。止まらなくなったら Ctrl + c で強制的に止められる。

もうひとつ気を付けたいのが、for f in *.txt のようなワイルドカードを使う場合に、条件に合うファイルが1つも無いときの挙動だ。bash の既定では、一致するものが無いと *.txt という文字列がそのまま変数に入ってしまい、存在しないファイル名を処理しようとして妙な結果になることがある。

つまずきfor f in *.txt で一致ファイルが無いと、*.txt という文字列がそのまま変数に入る。処理前に有無を確かめると安全。

処理の冒頭で対象ファイルの有無を確かめる、あるいはファイルが存在するかを if で点検してから本処理に進む、といったひと手間を入れると、こうした想定外を避けられる。

「for は決まったリストを1つずつ、while は条件が続く間ずっと」という性格の違いを押さえ、カウンタの更新と終了条件、そして break と continue による流れの制御を意識すれば、ループは安全で強力な道具になる。

多数のファイルへの一括処理や、ログを1行ずつ点検する定型作業など、手作業では骨の折れる仕事を、ループは数行で確実にこなしてくれる。

この項目に出てくる用語

ループるーぷ
同じ処理を繰り返す制御構造。for と while が代表的。

関連コマンド

echoread

▶ 学習アプリでこの続きを学ぶ・演習する