コマンドプロンプトで FOR ループなどを使っているときに 「あれ? 変数の値が変わらない??」ということがあります。
例えば、バッチファイルに次のように書いてあるとします。
FOR /F %%i IN ('SET') DO ECHO %%i
これは、コマンド SET の実行結果をずらっと表示します。
この結果の件数を取得するためにカウンタを付けたとします。
SET COUNT=0 FOR /F %%i IN ('SET') DO SET /A COUNT=%COUNT%+1 ECHO %COUNT%
上手く行きそうなのですが、結果は 1 が出力されます。
これは変数の“即時展開”というもので、 ループの中の %COUNT% が先に評価されてしまうので 結果的には次のような処理になってしまうためです。
SET COUNT=0
FOR /F %%i IN ('SET') DO SET /A COUNT=0+1
ECHO %COUNT%
対応として“遅延環境変数”を使うという方法があります。
遅延環境変数は、名前の通り遅延して変数を評価してくれるわけですが
デフォルトではオフ、CMD.exe のオプションやレジストリの変更や
SETLOCAL での指定が必要になります。
(詳しくは CMD /? してください)
今回は SETLOCAL を使って見ます。
次のように SETLOCAL で enabledelayedexpansion を指定して ENDLOCAL で終わります。 ( ENDLOCAL は省略可です。)
さらに遅延評価する変数は "%" ではなく "!" で囲みます。
SETLOCAL enabledelayedexpansion SET COUNT=0 FOR /F %%i IN ('SET') DO SET /A COUNT=!COUNT!+1 ECHO %COUNT% ENDLOCAL
これで想定していた結果が返ります。
(試す場合はファイルに保存して実行してください)
遅延環境変数を使わないで CALL を使う方法もあります。
SET COUNT=0 FOR /F %%i IN ('SET') DO CALL SET /A COUNT=%%COUNT%%+1 ECHO %COUNT%
これでも同じ結果が返ります。
CALL の中で "%" が二重になっていることに注意してください。