Windows bat のFORやIFでは遅延環境変数で変数を扱う

Windows bat のFORにおけるハマりポイント

WIndows batでバッチを作成してする際に良くハマるのが、FORやIFで変数が上手に展開できない問題です。

例えば、このようなバッチを作成した場合

@echo offset num=0for /l %%n in (1,1,10) do (  set a=%%n回目  echo %a%)

頭の中ではこのように出力されると考えますが、

1回目2回目3回目4回目5回目6回目7回目8回目9回目10回目

実際にはこのように変数に値が代入されることなくエラーが出力されます。

ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。ECHO は <OFF> です。

これは、仕様の問題で、括弧()をつかったブロック文を作った場合、

ブロックに入った瞬間に、ブロック内に何行あろうと1行と見なしてコードを読み込み内部の環境変数が全て展開されるためです。

つまりは、「set a=%%n回目」で変数を代入する前に「echo %a%」で変数が展開されてしまうためです。

これを解決するためには「遅延環境変数の展開」を利用します。

遅延環境変数の展開とは

遅延環境変数の展開をつかうと、変数を展開するタイミングをコードを読み込みでなく、変数を使う処理にたどり着いたタイミングとすることができます。

その結果、括弧内であっても変数に値を代入してから変数を展開することになるので、想定通りの変数を扱うことができます。

広告

遅延環境変数の展開を使った対応方法

では、実際に遅延環境変数の展開を使ってbatを修正します。

ポイントは2つです。

ポイント

  1. setlocal EnableDelayedExpansionを追加
  2. 変数の展開は「%」ではなく「!」を使う

実際にコードを修正するとこのようになります。

@echo offrem ポイント1setlocal EnableDelayedExpansionset num=0for /l %%n in (1,1,10) do (  set a=%%n回目 rem ポイント2  echo !a!)endlocal

実行結果はこのようになり変数が想定通り展開できるようになります。

1回目2回目3回目4回目5回目6回目7回目8回目9回目10回目