Windows のバッチファイルでは、環境変数の展開方法が2つある。
1つは即時変数展開で、もう1つが遅延変数展開と呼ばれるものだ。
即時変数展開
通常、バッチファイルの環境変数はコマンドを読み取るときに展開される。
(この動きを即時変数展開という)
たとえば以下のような IF 文があったとする。
set VAR=A
if %VAR% == A (
set VAR=B
echo %VAR% )
まず環境変数 VAR に A を入れ、それに続く IF 文の中で VAR に B を入れている。
その後 VAR の値を出力しているので、出力結果は B となりそうだが、実際に出力されるのは A となる。
なぜなら IF 文とそれに続く括弧内の複数コマンドにある環境変数は、 IF 文を読み取った時点の値で展開されるから。
つまり以下の IF 文は、、、
if %VAR% == A (
set VAR=B
echo %VAR% )
↓ 実際には以下のように1文で解釈される。
if %VAR% == A set VAR=B & echo %VAR%
で、1文で読み取られたコマンドにある環境変数はその時点の値 A で展開される。
if %VAR% == A set VAR=B & echo %VAR%
| | if A == A set VAR=B & echo A
よって、最後の echo コマンドで出力される結果は A となる。
遅延変数展開
環境変数の展開をコマンドの読み取り時ではなくコマンドの実行時にするには、遅延環境変数の展開を有効にする。
遅延環境変数の展開は setlocal
コマンドに enabledelayedexpansion
オプションを付けると有効になる。
endlocal
コマンドの実行、またはバッチファイルの終わりに到達すると無効になる。
遅延環境変数を展開するには、変数名を %
ではなく !
で囲む。
冒頭のバッチを遅延環境変数の展開を使って書き換えると以下のようになる。
このバッチを実行すると B と出力される。
setlocal enabledelayedexpansion
set VAR=A
if %VAR% == A (
set VAR=B
echo !VAR! )
余談。ローカル環境変数の話
setlocal
はローカル環境変数の使用を開始するコマンドである。
endlocal
コマンド実行で、ローカル環境変数の使用は終了になる。
setlocal
および endlocal
コマンドを実行するタイミングで環境変数の値が変わることがあるので注意したい。
以下のバッチを実行すると B → A と出力される。
set VAR=A
setlocal ← ローカル変数の使用開始
set VAR=B ← ここで VAR に設定した内容はローカル環境変数が有効な間のみ
echo %VAR% ← 出力結果は B
endlocal ← ローカル変数の使用終了 echo %VAR% ← 出力結果は A