目次
for文の中で値を変化させる
for文の中で値を変化させたい場合はfor文全体を、「setlocal enabledelayedexpansion」と「endlocal」で挟みます。また、for文内で使用する変数は「%」ではなく「!」で囲みます。
1 2 3 4 5 |
setlocal enabledelayedexpansion [for文 ※変数は「!」で囲む] endlocal |
以下の例は「for」を使って変数「sum」に1から10までを足していくプログラム「for_sum.bat」です。
1 2 3 4 5 6 7 8 9 10 11 |
@echo off setlocal enabledelayedexpansion set sum=0 for /l %%n in (1,1,10) do ( set /a sum=!sum!+%%n echo !sum! ) endlocal |
3行目と11行目に「setlocal」コマンドを記述してfor文を囲んでいます。また、for文の中の変数「sum」は「!」を使って囲っている点に注目です。
以下が実行結果です。
よくある間違いとして、「setlocal enabledelayedexpansion」を書き忘れたり、「!」ではなく「%」で囲んだりするとうまくいきません。
「enabledelayedexpansion」とは
「enabledelayedexpansion」は「遅延環境変数の展開」と呼ばれるものです。聞きなれない言葉ですが、そんなに難しいことではありません。「遅延環境変数の展開」について詳しく説明していきましょう。
まず、「環境変数」とは、前節のプログラムでいう「sum」のような変数のことです。「環境変数」=「変数」と思ってもかまいません。
次に、「環境変数の展開」とは、変数の値を代入することです。前節のプログラムの「set sum=0」や「set /a sum=!sum!+%%n」の部分です。
「遅延」は遅らせることですので、「遅延環境変数の展開」とは「変数に値が代入されるのを遅延させる(遅らせる)」という意味になります。では、これは一体どうゆうことでしょう。
以下のプログラムを考えます。
1 2 3 4 5 6 7 8 9 10 11 |
@echo off set name=tanaka echo 始めの名前=%name% if "%name%"=="tanaka" ( set name=yamada echo 途中の名前=%name% ) echo 最後の名前=%name% |
これを実行すると、3回の名前の表示はどうなるでしょうか。「if」文の中の変数「途中の名前」は直前の7行目で変数「name」に「yamada」を代入しているので、3度の名前の表示は、
始めの名前=tanaka
途中の名前=yamada
最後の名前=yamada
となって欲しいですが、実行結果は以下の通りです。
「途中の名前」が「tanaka」となってしまっています。
この原因は、バッチプログラムの「if」文全体は全ての行が同時に読み込まれるためです。つまり、6行目の「if」コマンドが実行されるのと同時に「if」文内のプログラムがすべて同時に読み込まれるということは、7行目の変化を反映しないまま、8行目の代入を行ってしまうのです。この時点では、「%name%」には「tanaka」が入っていますので「途中の名前」には「tanaka」が入っていたのです。
つまり、上記のプログラムは、
1 2 3 4 5 6 7 8 9 10 11 |
@echo off set name=tanaka echo 始めの名前=tanaka if "tanaka"=="tanaka" ( set name=yamada echo 途中の名前=tanaka ) echo 最後の名前=yamada |
と同意であり、8行目には「tanaka」が使用されています。
これを防ぐのが、「enabledelayedexpansion」です。「enabledelayedexpansion」は「遅延環境変数の展開」であり、「変数に値が代入されるのが遅延させる(遅らせる)」という意味でした。すなわち、同時に変数を代入するのではなく、変数の代入をコマンドを一行ずつ読み込んでいく時に遅らせるのです。
すると、「echo 途中の名前=%name%」の「%name%」部分はその直前の「set name=yamada」を読み込んだ後に置き換えられるため、変更後の名前が出力されます。
以下、「enabledelayedexpansion」を追加して修正したプログラムです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@echo off setlocal enabledelayedexpansion set name=tanaka echo 始めの名前=!name! if "!name!"=="tanaka" ( set name=yamada echo 途中の名前=!name! ) echo 最後の名前=!name! endlocal |
以下実行結果です。
思い通りの結果が得られました。
「%」ではなく「!」を使用していることに注意しましょう。
すごく助かりました。
ありがとうございます。