シェルスクリプトのwhileは「条件が満されているあいだ処理を繰り返す」という「繰り返しの制御文」だ。
if文とおなじくtestコマンドを使用して条件式をたてることが出来る。for文とくらべ複雑な条件式がたてられ、比較的柔軟だ。
このページではwhileについて使い方をご紹介する。シェルスクリプトを書くのであれば覚えておこう。
目次
一般的な書式について
while [ 条件式 ]
do
処理…
done
実際のところtestコマンドを使用しなかった場合でも、値の結果が「真」になれば繰り返し処理をしてくれるので、コマンド結果を条件として扱うことも可能だ。例は後半に後述する。
whileのサンプルコード
実際にwhileでの動きを見てみよう。
サンプルコード
vi while-ex1.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/usr/bin/bash #変数作成 declare -i COUNTER declare -i TMP_NUM COUNTER=0 #入力受付 read -p "何回繰り返しますか?:" TMP_NUM #COUNTERの値がTMP_NUMより小さければ「真」となる。 while [ "$COUNTER" -lt "$TMP_NUM" ] do echo "$COUNTER"回目の繰り返しです。 #COUNTER=` expr $COUNTER + 1` と記述しても同じ挙動になる。 let COUNTER++ done |
実行結果
$ ./while-ex1.sh
1 2 3 4 5 6 |
何回繰り返しますか?:5 0回目の繰り返しです。 1回目の繰り返しです。 2回目の繰り返しです。 3回目の繰り返しです。 4回目の繰り返しです。 |
letについて
整数を使った演算を処理するコマンドだ。四則演算にくわえインクリメント処理(1ずつ増やす)、ディクリメント処理(1ずつ減らす)などが可能になっている。
例えば
$ let var=10+10; echo $var
$ var=10; let var++; echo $var
となる。
もう少し実践的に
無限ループとBreak
whileは意図的に無限ループをおこないたいときにも使われる。無限ループとは永遠にwhileの外に抜け出すことができず、処理を繰り返すことだ。
しかし基本的に中でif文などの条件分岐を使い抜けだす条件を作るのが一般的だ。このとき抜けだす為の条件式に気をつけよう。抜けだす為の条件式をあやまると無限ループから抜けだせなくなる。
「while :」や「while true」や「while [ 1 ]」とすると無限ループが発生する。
サンプルコード
vi while-ex2.sh
1 2 3 4 5 6 7 8 9 10 11 12 |
#!/usr/bin/bash #条件がつねに「真」となる while : do echo "ループします。" read -p "処理を終了しますか?N or y:" if_y_or_no #breakへの糸口 if [ "$if_y_or_no" = "y" ]; then echo "終了します。" break fi done |
実行結果
$ ./while-ex2.sh
1 2 3 4 5 6 7 8 9 |
ループします。 処理を終了しますか?N or y: ループします。 処理を終了しますか?N or y:N ループします。 処理を終了しますか?N or y:n ループします。 処理を終了しますか?N or y:y 終了します。 |
抜けだせなくなる初歩的な例
vi while-bad-ex1.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/bin/bash declare -i COUNTER declare -i TMP_NUM TMP_NUM=1 COUNTER=1 while : do echo "$COUNTER"回目の繰り返しです。 let COUNTER++ # COUNTER++が処理された後、COUNTERがTMP_NUMより小さくなることはないため、条件が「真」になることはない。 if [ "$COUNTER" -le "$TMP_NUM" ]; then echo "終了します。" break fi done |
通常この様な書き方はしないが、一例としてとらえてほしい。
なにかしらの無限ループをする場合条件分岐で「break」への糸口をつくるが、その条件分岐を間違えると抜けだせなくなる。
コンピュータプログラムは基本的に「記述規則のエラー」は検出できるが、処理内容が「意図的かどうか?」は判別しないのである。良くも悪くも愚直なのだ。
無限ループが止まらなくなったら
意図しない無限ループが発生した場合は「Control + c」を連打すると止められる。
条件式にはtest以外も設定可能
条件式にはtest以外を設定することもできる。典型的な実用例としては下記のようなものがある。
サンプルコード
vi while-ex3.sh
1 2 3 4 5 6 7 |
#!/usr/bin/bash #readで一行ずつtestfile.txtの内容を読み込みwhileでそれを繰り返す。 #testfile.txtの内容がfile_lineに代入される。 while read file_line do echo $file_line done < "testfile.txt" |
実行結果
$ cat testfile.txt
1 2 3 |
aaa bbb ccc |
$ ./while-ex3.sh
1 2 3 |
aaa bbb ccc |
continue文について
whileなどの文の先頭に戻る。結果continue文を実行した場合、後ろに書いてある文は実行されない。
vi while-ex4.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/usr/bin/bash declare -i VAR VAR=0 while : do echo VARは"$VAR"です。 read -p "VARをインクリメントしますか?Y or n or help": PP_VAR case $PP_VAR in "n" ) break ;; "help" ) echo "デフォルトではインクリメントを行います。中止したい場合はnを押してください。";continue ;; esac let VAR++ done |
実行結果
$ ./while-ex4.sh
1 2 3 4 5 6 7 |
VARは0です。 VARをインクリメントしますか?Y or n or help: VARは1です。 VARをインクリメントしますか?Y or n or help:help デフォルトではインクリメントを行います。中止したい場合はnを押してください。 VARは1です。 VARをインクリメントしますか?Y or n or help:n |
その他:似たり寄ったりなコマンド
時代とともに変化しつづけてきたLinuxはことによりけり「似たり寄ったりな結果になるコマンド」が存在することがある。
今回のスクリプトの例でletコマンドを使いCOUNTERの値を増やしたがexprでも同じことが可能だ、もしくはbcなどのコマンドを使用しても問題ないだろう。
どれを使うか迷うかもしれないが、基本的な方針としては可読性の高いものを選択するというのも一つの基準だ。しかし、なにかしらのこだわりなどがある場合など、最終的にユーザの判断にゆだねられる。
LinuxやUnixというのは方法、選択肢を多く提供してくれるシステムだ。最初は選択肢の多さにとまどうかもしれないが「状況が使うべきコマンドを選ぶ」ことも多い、ケースバイケースで使っていこう。
まとめ
このページではシェルスクリプトのwhileについてまとめてご紹介した。
forももちろん使うが、whileも活躍する場面が多いため、ぜひ理解して使いこなせるようになっておこう。
×永遠と
○永遠にor延々と
ご指摘いただきありがとうございます。
一部文章におかしな部分がありましたので訂正いたしました。
引き続き、ご愛読のほど、よろしくお願いいたします。
while文のサンプルコードの1番最初の、read -p の直後にダブルコーティションが抜けているのでエラーに。
read -p 何回繰り返しますか?: TMP_NUM
↓
read -p "何回繰り返しますか?:" TMP_NUM
が正確なコードになるかと思われます。
と思いましたが、1文なので問題なしですね。。
英文で質問文を作成したので、2語以上になるため""が必要となりエラーでした。
失礼しました。。。
こちらのread -p のサンプル4ですと、1文でも""を付けて頂いているので、統一したほうが親切かもしれませんね。
https://eng-entrance.com/linux-shellscript-keyboard
いつもご愛読いただきありがとうございます。
ご指摘頂きました通り、readコマンドの構文としては一文で済む場合にはダブルクオートで括らなくても動作しますが、間にスペースなどを挟んだ場合にはダブルクオートが必須となります。サンプルプログラム内においては不要な実行エラーを防ぐ意味でも一律で括る方が宜しいかと思います。該当記事につきましては修正させて頂きました。
今後とも、ご愛読のほどよろしくお願いいたします。