for と while によるループ

ShellBeginner
オンラインで実践に進む

はじめに

1,000 通の手紙に署名しなければならない状況を想像してください。1 通なら簡単ですが、1,000 通となると退屈で手も痛くなります。プログラミングでは、このような退屈な繰り返し作業を避けたいものです。

そこで使うのが ループ です。ループを使うと、コンピューターに「リストの各項目に対して処理を繰り返す」または「条件が変わるまで処理を続ける」と指示できます。

コンピューターは繰り返し作業が得意で、人間は苦手です。そのため、ループは自動化の中心的な仕組みです。同じコマンドのパターンを何度も手動で実行しているなら、そこにはループを使える可能性があります。

この実験では、独自のデジタル作業ラインを作成します。

  1. カウンター:数を自動的に数えるループ(for ループ)。
  2. 作業担当者:複数のファイルを 1 つずつ処理するループ(ファイルを扱う for ループ)。
  3. 監視役:目標が達成されるまで処理を続けるループ(while ループ)。

数値のループ(For ループ)

for ループはチェックリストのようなものです。項目のリストを用意し、そのリストの各項目に対して処理を実行します。

これは Unix 系システムで特に役立つ自動化パターンの 1 つです。コンピューターは小さな処理を正確に繰り返すことが得意なので、ループを使えば、同じコマンドを何度もコピーせずに、1 つの項目に対する作業を多数の項目へ拡張できます。

まずは、最も簡単なリストである数値から始めます。コンピューターに 1 から 5 まで数えさせます。

最初に、作業ディレクトリを確認します。

cd ~/project

num_loop.sh という名前のスクリプトを作成します。

nano num_loop.sh

次のコードを入力します。

#!/bin/bash

for i in {1..5}; do
  echo "Number: $i"
done

作業ラインの仕組み:

  • for i in {1..5}:これは項目を供給する部分です。数値 1、2、3、4、5 を 1 つずつ変数 $i に渡します。
  • do:処理を開始します。
  • echo ...:各項目に対して実行する具体的な処理です。
  • done:現在の項目の処理を終了し、次の項目を取得します。

{1..5} の部分は、ブレース展開(brace expansion) と呼ばれる Bash の省略記法です。ループが開始される前に、Bash がこれを値のリストへ展開します。つまり、ループはあらかじめ用意されたリストを、1 項目ずつ処理しています。

保存(Ctrl+O)して終了(Ctrl+X)します。

スクリプトを実行可能にします。

chmod +x num_loop.sh
./num_loop.sh

次のように表示され、数値を数えていることを確認できます。

Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

ファイルのループ(For ループ)

数を数えるだけでも楽しいですが、ファイルを処理できると実用性が高まります。for ループは、*.txt のようなワイルドカードと組み合わせると非常に強力です。スクリプトに「このフォルダー内で見つかったすべてのテキストファイルに対して、X を実行する」と指示できます。

作業フォルダーには、すでにサンプルのテキストファイルがいくつか用意されています。それらを見つけるスクリプトを作成しましょう。

file_loop.sh という新しいファイルを作成します。

nano file_loop.sh

次のコードを入力します。

#!/bin/bash

echo "Listing text files:"
for file in *.txt; do
  echo "Found file: $file"
done

仕組み:

{1..5} のような数値ではなく、*.txt というパターンをループに渡しています。

Bash はフォルダー内を確認し、data1.txt や notes.txt のようにパターンに一致するすべてのファイルを見つけます。そして、それらを 1 つずつ $file という変数に渡します。

この一致処理は、ループ本体が実行される前に行われます。シェルは *.txt をファイル名のリストに展開し、for ループはそのリストを順番に処理します。そのため、シェルスクリプトではループと glob パターンを組み合わせると効果的です。

保存して終了します。

スクリプトを実行します。

chmod +x file_loop.sh
./file_loop.sh

次のような出力が表示されます。

Listing text files:
Found file: data1.txt
Found file: data2.txt
Found file: notes.txt

単に echo を使う代わりに、ファイルを移動する mv や、アーカイブを作成する zip を使ったらどうなるか想像してみてください。同じ 4 行のスクリプトで、10,000 個のファイルを数秒で処理できます。

条件付きループ(While ループ)

for ループは、数値やファイルなどのリストがある場合に便利です。しかし、リストがない場合はどうでしょうか。「何かが起こるまで処理を続けたい」場合はどうすればよいでしょうか。

この役割を担うのが while ループ です。これはサーモスタットに似ています。「部屋が寒い間は、暖房をつけ続ける」という動作です。

手動で 10 まで数えるスクリプトを作成しましょう。

while_loop.sh を作成します。

nano while_loop.sh

次のコードを入力します。

#!/bin/bash

counter=1

while [ $counter -le 10 ]; do
  echo "Count: $counter"
  ((counter++))
done

サーモスタットの仕組み:

  • while [ $counter -le 10 ]:条件です。「カウンターは 10 以下か?」を確認します。
    • YES の場合:ループに入ります。
    • NO の場合:停止します。
  • ((counter++)):更新処理です。カウンターに 1 を加えます。重要:この行を忘れると、カウンターは永遠に 1 のままになり、スクリプトも永遠に実行され続けます。これは「無限ループ」と呼ばれます。

ここで、for と while の重要な違いが分かります。for ループは通常、シェルからあらかじめ処理対象の並びを受け取ります。一方、while ループは条件に依存しており、スクリプトの実行中に、その条件が適切に変化するよう更新する必要があります。

((counter++)) は Bash の算術構文です。シェルに counter を数値として扱い、1 増加させるよう指示します。シェルスクリプトでは、テキスト処理と簡単な算術処理を組み合わせることが多いため、この構文は頻繁に登場します。

保存して終了します。

スクリプトを実行します。

chmod +x while_loop.sh
./while_loop.sh

for ループと同じように数を数えますが、仕組みは異なります。for はリストを順番に処理し、while は条件に基づいて処理を続けます。

まとめ

最初の自動化エンジンを作成しました。

この実験では、次の仕組みを身につけました。

  1. チェックリスト(for):{1..5} のように、定義済みの項目リストを処理する。
  2. バッチ処理(for *.txt):ディレクトリ内のすべてのファイルを自動的に処理する。
  3. サーモスタット(while):特定の目標または上限に達するまで処理を繰り返す。

これらのループは、スクリプトを支える基本的な仕組みです。手作業で 1,000 回クリックする作業を、コンピューターなら 1 秒で実行できる処理に変えてくれます。