とある条件を満たすまで処理を繰り返すというプログラムを作りたい時はforやwhileを使います。bashに限らず様々なプログラミング言語で登場します。
for文で変数に値を入れていくパターン
bashで最もシンプルなfor文の基本の型は
# for 変数名 in 値のリスト; do コマンド $変数名 ; done
リストの一番目の値を変数に入れてコマンド実行、二番目の値を変数に入れてコマンド実行というのを繰り返します。
- 変数名 i (integer[整数]の頭文字?)をよく見るが、なんでも良い var とか
- 値のリスト 数字でも文字でも良い
- コマンド 変数をコマンドに入れないと、ただ値のリストの数だけコマンドを繰り返し実行
- done ただの終わりの合図
- ; セミコロンは意味の区切りのために必須
for文は値のリストが尽きるまで順番に変数名に入れて繰り返します。
指定回数コマンドを繰り返す例
変数iにスペースをあけて記述するとスペース区切りで数字のリストを作れます。
下記の例では1~5の数のリストを作っています。
# for i in 1 2 3 4 5 ; do echo "ランキング第" ;done
ランキング第
ランキング第
ランキング第
ランキング第
ランキング第
こちらの例では5回コマンドを繰り返し実行という意味になります。
リストの値を変数に入れて繰り返す例
コマンド中に変数 i を展開するように書くと、リストの値が変数に代入されて実行されます。
# for i in 1 2 3 4 5 ; do echo "ランキング第"${i}"位" ;done
ランキング第1位
ランキング第2位
ランキング第3位
ランキング第4位
ランキング第5位
こうすると変数iが展開されるのでランキング何位という文字がたくさん書けます。
ブレース展開で楽に数字リストを記述する
1~100の数字のリストをスペース区切りで書くのはめんどくさいです。
数列式のようにかけると便利ですね。bashではブレース展開という表記でもっとシンプルに書くことができます。
1~100の数字をブレース展開で表現する
# for i in {1..100} ; do echo "ランキング第"${i}"位" ;done
{1..100}は1~100の数字を用意したのと同じ意味
1~100位までかける
文字もブレース展開で表現できる
# for i in {a..z} ; do echo "ランキング第"${i}"位" ;done
ランキング第a位
ランキング第b位
ランキング第c位
ランキング第d位
ランキング第e位
:
;
ランキング第z位
もし数字が大きくなればなるほどブレース展開で書くと楽ですね
数字の追加数も1ではなく2ずつ加算のように指定できます。
# for i in {1..10..2}; do echo $i ; done
1
3
5
7
9
条件式を書くパターン
forといえばこのパターンかも?
複雑に見えるかもしれませんが基本はこれまでと同じです。
# for ((初期値; 条件式; ループ処理)); do コマンド $変数名 ; done
書いてあることはさっきと一緒です。こちらの書き方ではループ時の処理が書ける点や細かい条件が書きやすいです。
具体例を見てみましょう。
iは0から始めて5まで1づつ加算というのは下記のように書きます。
# for (( i=0; i<=5 ;i++)) ;do echo "ランキング第$i位" ;done
ランキング第0位
ランキング第1位
ランキング第2位
ランキング第3位
ランキング第4位
ランキング第5位
forは無限ループに気をつける
ループ処理はiの数字を減らしていくパターンも描けます
# for (( i=0; i<=5 ;i--)) ;do echo "ランキング第$i位" ;sleep 1;done
ランキング第0位
ランキング第-1位
ランキング第-2位
ランキング第-3位
ランキング第-4位
ランキング第-5位
ランキング第-6位
:
わざわざsleep 1を入れているのは、初期値0から1ずつ減らしていくのは条件式のiが5以下という条件を一生満たさずに無限ループするからです。
1秒のスリープを入れないと機械の全力1を無限に減らし続けるので大きな負荷がかかって最悪停止します。
無限ループはプログラムな重大なバグなので注意しましょう。
条件は加算以外にも引き算や掛け算も記述可
ループ処理には任意の値を足していったり加減乗除が可能です
# for (( i=0; i<=5 ;i=i+1 )) ;do echo "ランキング第$i位" ;sleep 1;done
ランキング第0位
ランキング第1位
ランキング第2位
ランキング第3位
ランキング第4位
ランキング第5位
# for (( i=2; i<=15 ;i=i*2 )) ;do echo "ランキング第$i位" ;sleep 1;done
ランキング第2位
ランキング第4位
ランキング第8位
forで複数の変数を入れる
forでは一つの変数しか使えないわけではないです。
下の例ではiの他カンマ区切りでsの変数の初期値も設定しています。
# for (( i=2,s=3; i<=15 ;i=i*s )) ;do echo "ランキング第$i位" ;done
ランキング第2位
ランキング第6位
ちょっとした計算的なこともできそうですね
入力した変数を代入するパターン
コマンド入力時に書かれた引数を使って代入も可能です
# cat bin.sh
#!/bin/bash
for i in "$@" ;do echo "ランキング第$i位" ;done
上のようなスクリプトを作成
# ./bin.sh 1 2
ランキング第1位
ランキング第2位
引数として記述した全てが$@に代入されます。
for以外にもwhileを使ったループ処理の記述方があります。
シェルスクリプト、bashではwhile readを使ったループ処理も気軽にかけて使いやすいです。
whileでテキストを読み込んでループ処理する
whileは標準入力を受けてループ処理をかけるのでシェルスクリプトやワンライナーを書くときにシンプルに書けて便利です。
例えばこんな書き方ができます
# ls -1 | while read line ; do echo $line ; done
sa02
sa03
sa04
sa05
sa06
sa07
sa08
sa09
:
ls -1の値の標準出力をwhile readで受け取っています。
ファイルに書かれた名前のディレクトリを作成してみる
# cat directory_list
dir1
folder
here
# cat directory_list | while read line ; do mkdir $line ; done
↓下のコマンドと同じことをしている
mkdir dir1; mkdir folder; mkdir here
(結果) # ls
dir1 foler here ->3つのディレクトリができる
作成したいディレクトリのリストを読み込んで変数リストとして、ループ処理でディレクトリを作ることもできます。
while trueで無限に繰り返す
while trueと指定することで無限にリストを繰り返す処理がかけます。
# while true; do curl -IL google.com ; sleep 1 ; done
sleep1がないと無限ループするので注意してください。