Linuxでのfor(bash)の使い方です。便利ですが、多くの言語を使うとforの構文は良く混乱してします。
また、bashのforは、リストを区切り文字によって分けてループする特徴もあります。区切り文字の環境変数であるIFSを変更することで、より便利にリストのループを行うことができます。
forの構文
基本的なforコマンドの構文
1 |
for name [ [in [words …] ] ; ] do commands; done |
または、C言語風にも記述可能
1 |
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done |
基本的なforのコマンド
基本的なforコマンドの構文は下のようになります。
1 |
for name [ [in [words …] ] ; ] do commands; done |
一番オーソドックスなforコマンドの構文形式は以下のような形が多いです。
1 |
for 変数名 in リスト; do 繰り返すコマンド; done |
しかし、実用性があるかどうかを除いて、forの構文としてはリストを抜いて
1 |
for 変数名 in; do 繰り返すコマンド; done |
または、inも抜いて
1 |
for 変数名; do 繰り返すコマンド;done |
または、セミコロン(;)も抜いて、
1 |
for 変数名 do 繰り返すコマンド;done |
の形式もforコマンドの構文になります。
この4つのうち、「in」と「リスト」を抜いた2つの構文は
1 |
for 変数名; do 繰り返すコマンド;done |
1 |
for 変数名 do 繰り返すコマンド;done |
リストに「$@」という特殊なパラメータがリストの代わりに繰り返されます。「$@」は全ての引数リストを表すパラメータになります。
また、セミコロン(;)は改行にも置き換えることができます。
1 2 3 4 |
for 変数名 in リスト do 繰り返すコマンド done |
シェルスクリプトで記述する際にこのような形式が好まれます。
実際にforコマンドを使用する際は、
1 2 3 4 |
for name in aaa bbb ccc do echo $name done |
のように使用します。
C言語風のforコマンド
C言語風のforコマンドの構文は以下のようになります。
1 |
for (( expr1 ; expr2 ; expr3 )) ; do commands ; done |
具体的として、数字を列挙する場合は
1 2 3 4 |
for ((i=1; i<10; i++)) do echo $i done |
で1から9までの数字を列挙することができます。
IFS
IFSとは、シェルが文字を読み取る際に区切り文字として使われる変数です。デフォルトでは、スペース、タブ、改行の3つの区切り文字が設定されています。
例えば、ファイルの名前のリストでforコマンドを用いる場合、うまく動作しません。
1 2 3 4 5 6 7 |
#カレントディレクトリにスペースがあるファイルが存在するとうまく動作しません for name in * do if [ -f $name ]; then cp $name $name.bak fi done |
その場合はIFSを設定し直すことで、forコマンドをうまく動作させることができます。
1 2 3 4 5 6 7 8 |
#スペースがあるファイルが存在してもうまく動作します IFS=$'\n' for name in * do if [ -f $name ]; then cp $name $name.bak fi done |
また、IFSを代入するときに用いた「$''」の構文によって、ANSI-C標準の「\n」や「\t」などの特殊文字を利用できるようになります。
システムの影響などを考える場合、IFSをローカル変数にしたり、IFSのバックアップを取って使用するのも良い手だと考えられます。
1 2 3 4 5 6 7 8 9 |
###ローカル変数を用いる方法### local IFS=$'\n' ###IFSのバックアップを取る方法### IFS_TMP=$IFS IFS=$'\n' #IFSを戻す IFS=$IFS_TMP |
for文の展開されている内容を確認
setコマンドのxオプションを用いることでfor文の展開されているコマンドの内容を確認することができます。
1 |
set -x |
「set -x」を用いた場合、
1 2 3 4 |
for name in aaa bbb ccc do echo $name done |
の実行結果は、
1 2 3 4 5 6 7 8 9 |
+ for a in aaa bbb ccc + echo aaa aaa + for a in aaa bbb ccc + echo bbb bbb + for a in aaa bbb ccc + echo ccc ccc |
になります。
また、
1 2 3 4 |
for ((i=1; i<10; i++)) do echo $i done |
の実行結果は、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
+ (( i=1 )) + (( i<10 )) + echo 1 1 + (( i++ )) + (( i<10 )) + echo 2 2 + (( i++ )) + (( i<10 )) + echo 3 3 + (( i++ )) + (( i<10 )) + echo 4 4 + (( i++ )) + (( i<10 )) + echo 5 5 + (( i++ )) + (( i<10 )) + echo 6 6 + (( i++ )) + (( i<10 )) + echo 7 7 + (( i++ )) + (( i<10 )) + echo 8 8 + (( i++ )) + (( i<10 )) + echo 9 9 + (( i++ )) + (( i<10 )) |
になります。
「set -x」の機能をオフにするには
1 |
set +x |
を使用すれば、元に戻すことができます。
参考
GNU Bash manual(https://www.gnu.org/software/bash/manual/)