while / until
『while』はコマンドの終了ステータスが真(0)の間ループを繰り返します。『until』はその逆で、偽になる間繰り返します。ファイルを1行ずつ読み込む処理でも頻繁に使います。
構文
while ループで繰り返します。
while 条件; do
処理
done
until ループで繰り返します(条件が偽の間繰り返します)。
until 条件; do
処理
done
ファイルを1行ずつ読み込みます。
while IFS= read -r line; do
処理
done < ファイル名
パイプ経由で読み込みます(サブシェル注意)。
コマンド | while IFS= read -r line; do
処理
done
無限ループです。
while true; do
処理
done
構文パターン一覧
| パターン | 概要 |
|---|---|
| while [ 条件 ] | 条件が真の間ループを繰り返します。 |
| while (( 条件 )) | 算術条件が非ゼロの間繰り返します。 |
| until [ 条件 ] | 条件が偽の間ループを繰り返します。 |
| while true | break で明示的に抜けるまで無限に繰り返します。 |
| while IFS= read -r line | ファイルを1行ずつ安全に読み込みます。 |
| break | ループを途中で終了します。 |
| continue | 現在のイテレーションをスキップします。 |
サンプルコード
基本的な『while』ループでカウンタを1から5まで処理します。
while_count.sh
#!/bin/bash
count=1
while [ $count -le 5 ]; do
echo "カウント: $count"
(( count++ ))
done
bash while_count.sh カウント: 1 カウント: 2 カウント: 3 カウント: 4 カウント: 5
なお、while 文はターミナルでも直接入力できます。『do』の後で Enter を押すと『> 』マークが表示され、これは「まだ入力が続く」というサインで、『done』を入力すると実行されます。
count=1; while [ $count -le 5 ]; do
echo "カウント: $count"
(( count++ ))
done
カウント: 1
カウント: 2
カウント: 3
カウント: 4
カウント: 5
『until』は条件が偽の間ループします。『while』の逆の動作です。
until_count.sh
n=0
until [ $n -ge 5 ]; do
echo "n = $n"
(( n++ ))
done
bash until_count.sh n = 0 n = 1 n = 2 n = 3 n = 4
ファイルを1行ずつ読み込む定番パターンです。『IFS=』でスペースを保持し、『-r』でバックスラッシュをそのまま扱います。
read_lines.sh
while IFS= read -r line; do
echo "行: $line"
done < /etc/hosts
bash read_lines.sh 行: 127.0.0.1 localhost 行: 255.255.255.255 broadcasthost 行: ::1 localhost
無限ループはプロセス監視などに使います。『break』で明示的に抜けます。
monitor.sh
while true; do
if ! pgrep -x "myapp" > /dev/null; then
echo "myapp が停止しています。再起動します"
./myapp &
fi
sleep 60
done
『IFS』を変更してCSVファイルのフィールドを分割します。
csv_parse.sh
while IFS=',' read -r name score grade; do
echo "名前: $name, スコア: $score, 評価: $grade"
done <<'EOF'
Alice,95,A
Bob,78,C
Charlie,88,B
EOF
bash csv_parse.sh 名前: Alice, スコア: 95, 評価: A 名前: Bob, スコア: 78, 評価: C 名前: Charlie, スコア: 88, 評価: B
パイプ経由でコマンドの出力を1行ずつ処理します。
find_lines.sh
find . -name "*.php" | while IFS= read -r file; do
lines=$(wc -l < "$file")
echo "$file: $lines 行"
done
bash find_lines.sh ./index.php: 120 行 ./ajax.php: 85 行
概要
ファイルを行単位で処理するときは『while IFS= read -r line; do ... done < ファイル』が定番パターンです。『IFS=』を指定しないと行頭・行末の空白が削除され、『-r』を付けないとバックスラッシュが展開されてしまいます。
パイプ経由の while は別サブシェルで実行されます。そのため while ループ内で変数を更新しても、ループ終了後に外側のシェルから参照できません。変数を引き継ぐには入力リダイレクト(『< <(コマンド)』)や一時ファイルを使います。
リストの繰り返しには for の方が適しています。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。