UNIX & Linux コマンド・シェルスクリプト リファレンス』 by SUNONE

Release: 2005/08/21
Update: 2008/04/26

while 文の使用方法

while 文とは?

while 文は「ある条件が成り立っている間のみ繰り返し処理を実行する」といった、不定回の繰り返し処理を行う場合に使用するループ制御文である。 一般的に処理回数が明確である場合には for 文を用いるが、処理回数が開始時点では不明確な場合はこの while 文を用いる。 while 文は始めに指定された条件式の終了ステータスを判定し、結果が真である場合のみループ処理を継続する。 ループ毎に条件式を評価し真であれば処理を実行する。これを繰り返し、条件式が偽になった時点でループ処理をを終了する。

while 条件式
do
  処理
done

→ ループ処理を継続するための条件式を指定する。

while 文にはループの継続条件となる条件式を指定する。 条件式には test コマンドを使用するのが一般的だが、当然その他のコマンドも使用可能である。 while 文により条件式に指定したコマンドが実行され、その終了ステータスが「0」、つまり真である場合のみループが継続される。

while 文の使用例

一般的な使用方法 1 〜条件式に test コマンドを使用する〜

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 ループが終了する。

一般的な使用方法 2 〜条件式に test 以外のコマンドを使用する〜

今度は条件式に 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 ループが終了する。

一般的な使用方法 3 〜無限ループ〜

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 文に指定する条件式では表現しきれないような、複雑な終了条件を指定したい場合に使用するとよい。

ループを制御する

break コマンドでループを途中で終了する

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 コマンドに引数を指定して、多重ループを一気に抜けるテクニックは覚えておいて損はない。

continue コマンドでループをスキップする

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.