for 文の使用方法
for 文とは?
for 文は一定回数の繰り返し処理を行う場合に使用するループ制御文である。もしくはある値の集合に対して、それぞれの要素を処理するループ制御文である。
一般的には処理回数や、処理対象となる集合が明確な場合には for 文を使用する。その他の場合は while 文を使用することになる(シェルスクリプトでの for 文は決まった回数のループ処理というよりも、リストに対するループ処理といった方が正しいかもしれない)。
for 変数 in 値リスト
do
処理
done
→ ループに使用される値のリストと、値リストの各要素がループ毎に設定される変数を指定する。
for 文は値リストに指定された1つ目の値を変数に設定し、do
と done
の間の処理を実行する。処理後、同様にして値リストに指定された2つ目の値を変数に設定し、再び do
と done
の間の処理を実行する。3つ目以降も同様にして、全ての値リストが消化されるまでループし続ける。
for 文に指定する変数は、任意の変数を使用することができる。値リストにはリストとなる文字列の直接指定のほかに、複数の変数の値や、コマンド置換 (`command`
や $(command)
) を使用して、コマンドの実行結果を直接値リストとして指定することも可能である。もちろんそれら全てを同時に指定することも可能だ。
また、for 文はシェルスクリプトで使用するのみならず、コマンドラインからも直接使用することが可能だ (for 文は正確には for コマンドであるため)。
for 文の使用例
値のリストを直接指定する
for var in hoge fuga foo bar
do
…
done
→ 値リストに処理対象としたい文字列を全て列挙する。
処理対象とするものがすでに明確である場合は、その値を全て for 文の値リストとして指定する。
1 から 10 までの合計を計算する for 文の例
$ total=0
#↑集計用の変数を初期化。
$ for i in 1 2 3 4 5 6 7 8 9 10
> do
> total=`expr $total + $i`
> done
#↑for文を使用し、1~10を変数 total に加算していく。
$ echo $total
55
#↑変数 total を参照してみると、確かに加算されているのが分かる。
1 から 10 までの数字を表示する例 その1
$ for i in 1 2 3 4 5 6 7 8 9 10
> do
> echo $i
> done
1
2
3
4
5
6
7
8
9
10
1~10 までの数字がそれぞれループ毎に変数 i へ設定されるので、各値が 1 行ずつ計 10 行出力される。
1 から 10 までの数字を表示する例 その2
$ for i in "1 2 3" "4 5 6" "7 8 9 10"
> do
> echo $i
> done
1 2 3
4 5 6
7 8 9 10
クォートされている場合は、その塊の単位で変数 i へ設定されていることが確認できる。
前の例 (その1) と ""
以外はまったく同じだが、出力される内容はまったく違っている。for 文も他のコマンド等と同様に、""
で囲まれた文字列を一つの値とみなすため、出力される値は「1 2 3」「4 5 6」「7 8 9 10」の 3組 (3行) となる。
for 文使用例 補足
$ for i in 1 2 3 4 5
> do
> echo "Test."
> done
Test.
Test.
Test.
Test.
Test.
上記のように、変数 i はループ内では特に使用しなくとも問題ない。
for 文に指定した変数 (上記の場合は変数 i) は、for ループ内で必ず参照する必要はない。したがって、上記のように値の参照は行わずに、単純にループ回数を制限するためのみに使用する、といった使い方もできる。
変数の値を値リストに指定する
for var in $VALUE1 $VALUE2 … $VALUEn
do
…
done
→ 値リストに処理対象となる文字列が設定されている変数を指定する。
値リストには文字列の直接指定だけではなく、処理対象となる文字列が設定されている変数を指定することも可能である。
$ VALUE1="aaa"
$ VALUE2="bbb ccc ddd"
$ VALUE3="eee fff"
#↑変数に値リストとする値を設定する。
$ for i in $VALUE1 $VALUE2 $VALUE3
> do
> echo $i
> done
aaa
bbb
ccc
ddd
eee
fff
#↑変数を「""」で囲まない場合。
$ for i in "$VALUE1" "$VALUE2" "$VALUE3"
> do
> echo $i
> done
aaa
bbb ccc ddd
eee fff
#↑変数を「""」で囲んだ場合。
上記例のように、変数に設定されている値単位で値リストに指定したい場合は、変数内の空白を無視するために各変数を ""
で囲む必要がある。
for 文は値リストに指定された変数を展開してから実行されるので、(これは for 文以外にも当てはまることだが、) 常に変数展開後のイメージを考慮しながら記述するとよい。
コマンドの実行結果を値リストに指定する
for var in `コマンド`
do
…
done
→ ``
(バッククォート) でコマンドの実行結果を値リストとして使用する。
値リストには値の直接指定や変数だけではなく、``
(バッククォート) を使用することでコマンドの実行結果を指定することも可能である。
カレントディレクトリにある全テキストファイルの行数を取得する例
$ for var in `ls -1 *.txt`
> do
> wc -l $var
> done
9 file1.txt
33 file2.txt
28 file3.txt
62 file4.txt
11 file5.txt
#↑「 ls -1 *.txt 」で取得されたファイルに対し for 文で処理が実行されている。
$ ls -1 *.txt
file1.txt
file2.txt
file3.txt
file4.txt
file5.txt
#↑「 ls -1 」は検索したファイルを 1 ファイル 1 行でリスト表示する。
for i in *.txt
としても実行結果は変わらないので、そちらの記述方法のほうが効率的といえるが、どんな処理になるか一見して分かりづらいため、シェルスクリプトに詳しくない人には、この記述方法が理解されないことが多い。
筆者はシェルスクリプトの可読性を考慮して、for i in
と記述するようにしている。ls -1 *.txt
一定回数のループ処理を作成する
for i in `seq 1 N`
do
…
done
→ seq コマンドで連番を作成することにより、一定回数のループ処理を作成する。
前述の「コマンドの実行結果を値リストに指定する」の応用で、連番を出力するコマンドである seq コマンドにループ回数 N を指定することで、一定回数のループを簡単に作成することができる。
10 回のループ処理を作成したい場合は N に 10 を、50回のループ処理を作成したい場合は N に 50 を指定すればよい。
$ for i in `seq 1 7`
> do
> echo "$i 回目のループです。"
> done
1 回目のループです。
2 回目のループです。
3 回目のループです。
4 回目のループです。
5 回目のループです。
6 回目のループです。
7 回目のループです。
「7」を指定したので、7回のループ処理が作成・実行されているのが確認できる。
ループを制御する
for 文では while 文と同様に、
- ループの次のステップへ進む continue コマンド
- ループから抜け出す break コマンド
が使用可能である。
for 文でも while 文でも、この 2つのコマンドの使用方法には特に違いはないので、詳しい使用方法に関しては別ページの「ループを制御する」解説を参照してほしい。
C言語など他の言語と使用方法に関して違いはないので、そちらを知っている人には特に問題はないはずである。