Release: 2005/08/21
Update: 2008/04/26
UNIX & Linux コマンド・シェルスクリプト リファレンス > while 文の使用方法
while 文は「ある条件が成り立っている間のみ繰り返し処理を実行する」といった、不定回の繰り返し処理を行う場合に使用するループ制御文である。 一般的に処理回数が明確である場合には for 文を用いるが、処理回数が開始時点では不明確な場合はこの while 文を用いる。 while 文は始めに指定された条件式の終了ステータスを判定し、結果が真である場合のみループ処理を継続する。 ループ毎に条件式を評価し真であれば処理を実行する。これを繰り返し、条件式が偽になった時点でループ処理をを終了する。
while 条件式 do 処理 done
→ ループ処理を継続するための条件式を指定する。
while 文にはループの継続条件となる条件式を指定する。 条件式には test コマンドを使用するのが一般的だが、当然その他のコマンドも使用可能である。 while 文により条件式に指定したコマンドが実行され、その終了ステータスが「0」、つまり真である場合のみループが継続される。
while [ 条件式 ] do … done
→ if 文と同じように "[]" を使用して条件式を指定する。
おそらくこれがもっとも一般的な while 文の継続条件を指定する方法だと思う。 test コマンドの略式記述方法である "[]" の使用方法は「test コマンド」を参照してほしい。
キーボードから入力された文字が "a" である間のみ処理を続けるループを作ってみる。
while_a.sh
#!/bin/bash read key while [ "$key" = "a" ] do echo "ok" read key done
このシェルスクリプト while_a.sh の実行結果は、以下の通りとなる。
$ ./while_a.sh
b
$
※↑最初に "a" が以外が入力されると、継続条件が偽になるのでループ処理は1度も行われずにに終了する。
$ ./while_a.sh
a
ok
a
ok
a
ok
a
ok
b
$
"a" が入力されている間は条件式が [ "a" = "a" ] となるので、結果は真となりループ内の処理が実行される。 "b" が入力された時点で、条件式が [ "b" = "a" ] となり、結果が偽となるために while ループが終了する。
今度は条件式に test コマンドではなく、そのほかのコマンドを用いた while ループを作ってみる。
while read line do echo "$line" done <test.txt
while文にリダイレクションするには done の直後に記述する。 上記の例では while 文への入力に test.txt を指定している。 while 文にはこのテキストファイルから1行ずつ自動で入力され、条件式に指定した read コマンドがそれを変数 line に格納している。
$ cat test.txt 111 222 333 444 555 ※↑入力用のテキストファイルを用意する。 $ while read line > do > echo "$line" > done <test.txt 111 222 333 444 555 $ ※↑ファイルは 5 行目までしか無いため、6 回目の判定は偽となりループは 5 回で終了する。
上記例の while ループは始めに「read line」が実行され、変数 line に標準入力からの値が設定される。 通常、標準入力はキーボードから入力だが、今回はリダイレクション(<) でテキストファイル test.txt からの入力に切り替えられている。 そのため 1 回目のループではテキストファイルの 1 行目「111」が変数 line に設定される。 正常に read コマンドが実行されたため、コマンドの終了ステータスが真となることで条件式は真となり、while ループ内の echo コマンドが実行される。 その後もテキストファイルから入力が続きループが継続されが、使用したテキストファイルは 5 行目までしかないので、最終行の「555」を出力後に read コマンドが入力値なしのため失敗となる。 それによって read コマンドの終了ステータスが 1 となり、条件式が偽となることで while ループが終了する。
while :
do
…
if 条件式; then
break
fi
…
done
→ while 文の条件式にヌルコマンド(:)を指定し、break コマンドを実行する処理を記述する。
while 文の条件式にヌルコマンド(:)を指定することで、無限ループを作成することができる。 ヌルコマンドは終了ステータスが常に真となるため、while ループは終了することがなく無限ループとなる。 ループを抜けるには Ctrl+c で強制的に終了するか、while 文中に break コマンドを実行する判定文を記述する。
参考 〜 ヌルコマンドとは?
ヌルコマンドとは ":" で表され、何も処理を行わずに終了するコマンドである。 何も処理を行わないので、終了ステータスは常に真となる。
参考 〜 break コマンドとは?
break コマンドとは for 文や while 文、until 文で使用されるループを抜けるためのコマンドである。 このコマンドが実行されるとループの途中であっても、その時点でループは終了となる(do 〜 done の外に出る、つまり done の直後から再開される)。 通常、if 文と共に用いられ、「ある条件が成立したら実行しループを抜ける」といった使われ方をする。
下記は無限ループを break コマンドを使用して抜ける処理の例。
while_endless.sh
#!/bin/bash
while :
do
read key
if [ "$key" = "q" ]; then
echo "breakコマンドを実行します..."
break
else
echo "$keyが入力されました。"
fi
done
echo "無限ループを抜けました。"
exit 0
このシェルスクリプト while_endless.sh の実行結果は、以下の通りとなる。
$ ./while_endless.sh a ←キー入力 aが入力されました。 b ←キー入力 bが入力されました。 c ←キー入力 cが入力されました。 q ←キー入力 breakコマンドを実行します... 無限ループを抜けました。 $
このシェルスクリプトは「q」が入力されるまで同じ処理が繰り返される。 「q」が入力されると break コマンドが実行され、ループを終了する。 while ループを終了した後は while 文の done の直後から処理が継続される。
while 文中の if 文をさらに拡張すると、さまざまな条件でループを継続または終了することができる。 つまり無限ループは while 文に指定する条件式では表現しきれないような、複雑な終了条件を指定したい場合に使用するとよい。
while 条件式 do … break … done
→ break コマンドを実行することでループを途中で終了することができる。
ループの途中でエラーが発生した場合など、ループを強制的に終了させたいときには break コマンドを実行する。 無限ループを終了させたい場合にもこの break コマンドを使用する。 break コマンドに引数を指定することで、ネストされたループから一気に抜け出すことも可能である。
break コマンドに引数を渡して、ネストされたループを一気に抜ける処理を作成してみる。
while_break.sh
#!/bin/bash
while :
do
while :
do
read key
if [ "$key" = "q" ]; then
# 引数に指定された値を break コマンドに指定
break $1
fi
done
# $1 が2以上ならばここは出力されないはず
echo "2以上ならばここは実行されないはず。"
break
done
このシェルスクリプト while_break.sh の実行結果は、以下の通りとなる。
$ ./while_break.sh 1 a b c q 2以上ならばここは実行されないはず。 ※↑引数が 1 だったため、一気にループを抜けられずに echo コマンドが実行された。 $ ./while_break.sh 2 a b c q ※↑引数が 2 だったので、2重のループを一気に抜けたために、echo コマンドは実行されなかった。 $ ./while_break.sh 3 a b c q ※↑引数が 3 でも 2 の場合と同じ。
シェルスクリプトでネストされたループを必要とするような機会はほとんどないと思われるが、 break コマンドに引数を指定して、多重ループを一気に抜けるテクニックは覚えておいて損はない。
while 条件式 do … continue … done
→ continue コマンドを実行することで今回の処理をスキップし、ループの先頭に移動することができる。
ループ処理において、ある条件の場合のみ処理を行わずにスキップしたいときには、continue コマンドを実行する。 break コマンドと同様に、引数を指定することにより、ネストされたループ処理を一気にスキップすることが可能だ。
continue コマンドに引数を渡して、ネストされたループを一気にスキップする処理を作成してみる。
while_continue.sh
#!/bin/bash
# 初回 exit 回避用フラグ
SKIP="ON"
while :
do
if [ "$SKIP" != "ON" ]; then
echo "continue 2 が実行されました."
exit 0
fi
# 以降のループでは上の処理をスキップしない
SKIP=""
while :
do
if [ "$CNT" = "ON" ]; then
echo "continue が実行されました."
continue 2
fi
# continue フラグを立てる
CNT="ON"
continue
# continue フラグをオフにする
CNT=""
done
done
このシェルスクリプト while_continue.sh の実行結果は、以下の通りとなる。
$ ./while_continue.sh continue が実行されました. continue 2 が実行されました.
最初のメッセージは CNT フラグを立てた直後に、continue を実行したために出力されている。 そのメッセージ出力直後に、今度は continue 2 が実行されて、処理がひとつ上の while ループの先頭に移動している。 SKIP フラグは ネストされたループに入る直前でオフにされているので、continue 2 実行後はメッセージを出力後に exit している。
break number continue number
→ break コマンドと continue コマンドは引数に数値を指定することにより、ネストされた多重ループを越えた移動が可能になる。
引数に指定した数値の分だけ上の階層のループを対象に実行される。引数を省略した場合は、「1」を指定したのと同じ動作になる。
while :
do
# 1つ目のループ
・・・
while :
do
# 2つ目のループ
・・・
# 1つ目のループの先頭に戻る。
continue 2
・・・
# 1つ目のループから抜ける。
break 2
・・・
done
done
上記のような2重ループから抜け出すには、 break コマンドの引数に「2」を指定して実行する。 同様に2重ループの先頭(1行目の while ループ先頭)に戻るには、 continue コマンドの引数に「2」を指定して実行する。

Copyright© SUNONE All Rights Reserved.