2015年1月28日水曜日

バッチファイルの遅延環境変数の展開

バッチファイルの遅延環境変数の展開について知らなかったため、先日バッチファイル作成時にハマってしまった。調べればもっとわかりやすいサイトもあるが、自分でもスクリプト作って調査・確認をしたので備忘として残しておく。

環境変数の展開というバッチファイルの罠

バッチファイルは1行1行読み込みながらコマンドを解釈して処理を実行する。変数がある場合は、1行読み込んだ際に値を代入して処理をする。しかし、if文やfor文の場合は、if文の中身も含めて一気に変数に値を代入する(環境変数が展開される)という、バッチファイルならではの癖がある。

例を出そう。以下は1~10までを足し算するバッチファイルである。
rem 1~10までを足し算する
@echo off
set i=0
for /l %%X in (1,1,10) do (
set /a i=%i% + %%X
echo %i%
)
echo %i%
pause
exit 0
結果は55が最後に表示されることを期待するが、以下の通りうまくいかない。
0
0
0
0
0
0
0
0
0
0
10
続行するには何かキーを押してください . . .
なぜかというとfor文の()の中身は、for文開始時に変数iが0で展開されてしまうから。わかりやすく書くと、以下を実行していることと同一になってしまう(ループの最後は%%Xは10が入るので、それが変数iに代入されて終わる)。
rem 1~10までを足し算する
@echo off
set i=0
for /l %%X in (1,1,10) do (
set /a i=0 + %%X
echo 0
)
echo %i%
pause
exit 0

遅延環境変数の展開を有効化する

問題を解決するためには、以下2点を対応すれば良い。

  1. 最初に"setlocal enabledelayedexpansion"を書いて、遅延環境変数の展開を有効化
  2. 遅延環境変数は"%"ではなく"!"で囲む

試してみよう。
rem 1~10までを足し算する
@echo off
rem 遅延環境変数
setlocal enabledelayedexpansion

set i=0
for /l %%X in (1,1,10) do (
set /a i=!i! + %%X
echo !i!
)
echo %i%
pause
exit 0

結果。
1
3
6
10
15
21
28
36
45
55
55
続行するには何かキーを押してください . . .
以上の通り、想定される55の結果が表示された。