Bashループ完全ガイド!for・while・untilの基本構文と実用例
ループ文とは、プログラムに対して同じ処理を繰り返し実行させるための制御構造です。繰り返し実行される一連の命令は「ループ本体(ボディ)」と呼ばれます。
ループは、制御式の評価結果が0(偽)になるまで実行を続けます。制御式には任意のスカラー型のデータを指定できます。
シェル言語にも、反復処理を行うための構文が複数用意されています。この記事では、Bashが提供する各ループ構文を具体的なサンプルとともに解説します。
Bashで使える3種類のループ構文
- forループ
- whileループ
- untilループ
本記事は、連載「Bashチュートリアル」シリーズの一部です。
また、ループはネスト(入れ子)にすることも可能です。他の多くのプログラミング言語と同様に、Bashでも現在のループを途中で抜けるbreak文や、次の反復処理へスキップするcontinue文を利用できます。
Bash forループ(第1の書式)
forループは、反復回数がループ開始前に分かっている場合に適しています。Bashのforループには2つの書式があり、まずは基本形から紹介します。
for varname in list
do
commands ## ループ本体
done
上記の構文において:
for、in、do、doneはキーワードですlistは処理対象の項目リストですvarnameは任意のBash変数名です
この書式では、リスト内の各項目ごとに1回ずつ、do〜done間のコマンドが実行されます。ループを1回まわるたびに、現在の項目が変数 varname に格納され、ループ本体内でその変数を処理できます。リストには、スペース区切りの複数の単語を含む変数を指定することも可能です。なお、for文でリストを省略した場合は、シェルに渡された位置パラメータが使用されます。
forループ 例1:ZIPファイルをすべて展開する
次の例では、/root配下から「*.zip*」に一致するファイルを検索し、zipファイルと同じ場所に新しいディレクトリを作成して、そこにzipファイルの中身を展開します。
# cat zip_unzip.sh
#! /bin/bash
# .zip を含むファイルを検索
for file in `find /root -name "*.zip*" -type f`
do
# 拡張子 .zip を除いた名前を取得
dirname=`echo ${file} | awk -F'.' '{print $1}'`
# ディレクトリを作成
mkdir $dirname
# zipファイルをコピー
cp ${file} ${dirname}
cd $dirname
# 新しく作ったディレクトリ内でzipファイルを展開
unzip ${dirname}/$(echo ${file##/*/})
done
findコマンドがファイルのリストを返し、その1件ずつがループで処理されます- 各項目について、zipファイル名をもとにディレクトリを作成し、zipファイルをそのディレクトリへコピーしてから展開します
echo ${file##/*/}はパス部分を取り除き、ファイル名だけを取得するテクニックです
# ./zip_unzip.sh Archive: /root/test2/test2.zip extracting: t1/p extracting: t1/q extracting: t1/r extracting: t1/s extracting: t1/t extracting: t1/u extracting: t1/v Archive: /root/test1/test1.zip extracting: t/a extracting: t/b extracting: t/c extracting: t/d extracting: t/e
Bashと同様に、Awkでもforループやwhileループを利用できます。詳細は「AwkのWhileループとForループ」の記事を参照してください。
Bash forループ(第2の書式:C言語風)
もう1つのforループの書式は、C言語のfor文に似ており、「初期化」「条件」「更新」の3つの式を取ります。
for (( expr1; expr2; expr3 ))
do
commands
done
- 最初の反復の前に
expr1が評価されます。通常はループ用変数の初期化に使います expr2が真(TRUE)である限り、do〜done間の文が繰り返し実行されます- 各反復の後に
expr3が評価されます。通常はループカウンタの増加に使います
次の例では、指定した個数の乱数を生成します。
forループ 例2:n個の乱数を生成する
$ cat random.sh
#! /bin/bash
echo -e "How many random numbers you want to generate"
read max
for (( start = 1; start <= $max; start++ ))
do
echo -e $RANDOM
done
$ ./random.sh
How many random numbers you want to generate
5
6119
27200
1998
12097
9181
このスクリプトでは、forループが指定した最大回数分だけ乱数を出力します。RANDOM はBashの内部変数で、参照するたびにランダムな整数を返します。
Bash whileループ
シェルプログラミング言語が提供するもう1つの反復構文がwhile文です。
構文:
while expression
do
commands
done
上記のwhileループの構文において:
while、do、doneはキーワードですexpressionはスカラー値を返す任意の条件式です- while文は、条件式が真である限りコードブロックを実行し続けます
whileループ 例3:標準入力の内容をファイルに書き込む
次の例では、標準入力からデータを読み込み、ファイルへ書き込みます。
$ cat writefile.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to create" read file while read line do echo $line >> $file done $ sh writefile.sh Enter absolute path of the file name you want to create /tmp/a while for until $ cat /tmp/a while for until
この例では、ユーザーからファイル名を読み取り、標準入力から1行ずつデータを受け取って、指定されたファイルに追記していきます。EOF(終端)が入力されると read が失敗するため、そこでループが終了します。
大量のBashスクリプトを書く機会が多い方は、Vimのbash-supportプラグインを導入すれば、VimエディタをBash IDEとして活用できます。
whileループ 例4:ファイルの内容を読み込む
前の例では標準入力からデータを読んでファイルに書き込みました。今度は逆に、ファイルの内容を読み込んで標準出力へ表示します。
$ cat read.sh #! /bin/bash echo -e "Enter absolute path of the file name you want to read" read file exec <$file # 標準入力をファイルにリダイレクト while read line do echo $line done $ ./read.sh Enter absolute path of the file name you want to read /tmp/a while for until
この例では、読み込むファイル名を取得し、exec によって標準入力をファイルにリダイレクトしています。以降、標準入力はキーボードではなくそのファイルから供給されます。read コマンドは標準入力から1行を読み込むため、whileループはEOFが現れるまで標準入力を読み続けます。
Bash untilループ
until文は、構文も動作もwhile文と非常によく似ています。両者の唯一の違いは、until文は条件式が偽である限りコードブロックを実行するのに対し、while文は条件式が真である限り実行するという点です。
構文:
until expression
do
commands # ループ本体
done
上記のBash until構文では、until、do、done がキーワードで、expression は任意の条件式です。
untilループ 例5:ログファイルを監視する
この例ではログファイルのサイズを監視し、サイズが2000バイトに達した時点でそのコピーを取得します。
$ cat monitor.sh
file=/tmp/logfile
until [ $(ls -l $file | awk '{print $5}') -gt 2000 ]
do
echo "Sleeping for next 5 seconds"
sleep 5
done
date=`date +%s`
cp $file "$file-"$date.bak
$ ./monitor.sh
Sleeping for next 5 seconds
Sleeping for next 5 seconds
$ ls -l /tmp/logfile*
-rw-r--r-- 1 sss sss 2010 Jun 24 12:29 logfile
-rw-r--r-- 1 sss sss 2005 Jun 24 16:09 logfile-1277474574.bak
until文は、条件が真になるまでループ本体の実行を続けます。この例での条件は「ファイルサイズが2000バイトより大きいこと」なので、ファイルが2000バイトに達した時点でバックアップコピーが作成されます。
あわせて、以前の記事「Bash配列の実例集」も参考にしてください。
untilループ 例6:マシンの起動を待つ
この例は、対象マシンへssh接続する前に、そのマシンが起動するまで待機するために使います。pingが応答を返すようになると、untilループが終了します。
$ cat mac_wait.sh
#! /bin/bash
read -p "Enter IP Address:" ipadd
echo $ipadd
until ping -c 1 $ipadd
do
sleep 60;
done
ssh $ipadd
$./mac_wait.sh
Enter IP Address:192.143.2.10
PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data.
--- 192.143.2.10 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
PING 192.143.2.10 (192.143.2.10) 56(84) bytes of data.
64 bytes from 192.143.2.10: icmp_seq=1 ttl=64 time=0.059 ms
--- 192.143.2.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.059/0.059/0.059/0.000 ms
The authenticity of host '192.143.2.10 (192.143.2.10)' can't be established.
Are you sure you want to continue connecting (yes/no)? yes
untilループは、特定のイベントの発生を待つ手段として、コマンドライン上で非常に便利です。
-
Bashスクリプトでwhileループを使ってファイルを読み込むさまざまな方法
この記事では、Bashスクリプトでwhileループを使ってファイルを読み込む方法について詳しく解説します。ファイルの読み込みはプログラミングにおいて非常によく使われる操作であり、複数の方法とそれぞれの効率性を理解しておくことが重要です。Bashでは1つのタスクをさまざまな方法で実現できますが、常に最適な手段が存在するため、それを選ぶようにしましょう。whileループの基本ファイルの内容を読み込む方法を見る前に、まずwhileループの仕組みを簡単に復習しておきましょう。whileループは条件を評価し、条件が真である限り、指定されたコードブロックを繰り返し実行します。while [ CONDITI
-
楽しく学べる!Bash習得に役立つコマンドラインゲーム3選
学習は大変な作業であり、誰も「作業」そのものは好きではありません。つまり、Bashがどれだけ習得しやすい言語だとしても、やはり「勉強」という感覚を拭いきれないかもしれません。しかし、ゲームを通して学ぶなら話は別です。 ターミナルの使い方を教えてくれるゲームなど、そう多くは存在しないと思うでしょう。実際、その通りなのです。PCゲーマーならご存知の通り、FalloutシリーズにはVault内にターミナル式のコンピュータが登場し、テキストでコンピュータと対話するという概念に自然と親しめるようになっています。AlpineやEmacsに似たアプリケーションも登場しますが、残念ながらFalloutをプレイ