IF や FOR は1行で書いてしまわないといけないかというと、現代ではそうでもなく、丸括弧を使うと複数行に展開して書くことができます。
if "%1" == "a" (
echo arg is a
echo aaaaaaaa
) else (
echo arg is else
echo bbbbbbbb
)
ただし、環境変数の展開のタイミングが IF や FOR の実行前 なので、注意が必要です。たとえば、次のバッチファイルは X に 1 2 3 4 5
という値をセットしたいのですが、期待どおり動作しません。
@echo off
setlocal
set X=1
for %%I in (2 3 4 5) do (
set "X=%X% %%I"
)
echo X=%X%
endlocal
exit /b
$ f
X=1 5
ENABLEDELAYEDEXPANSION による遅延展開
回避策として SETLOCAL ENABLEDELAYEDEXPANSION
を使えば「!環境変数名!
」形式の環境変数の遅延展開が使えます。
@echo off
setlocal
SETLOCAL ENABLEDELAYEDEXPANSION
set X=1
for %%I in (2 3 4 5) do (
set "X=!X! %%I"
)
echo X=%X%
endlocal
exit /b
$ f
X=1 2 3 4 5
サブルーチン分離による遅延展開
問題点としては
- ENABLEDELAYEDEXPANSION の綴りが覚えにくい(お前だけや!)
-
SETLOCAL ENABLEDELAYEDEXPANSION
を実行する前の CMD の遅延評価モードが有効だったか、無効だったか分からないので、まったく副作用がないバッチファイルというわけではなくなってしまう
という点があります。そのため、筆者個人としては、下記のようにサブルーチンに分けてしまう方が好みです。
@echo off
setlocal
set X=1
for %%I in (2 3 4 5) do call :setx %%I
echo X=%X%
endlocal
exit /b
:setx
set "X=%X% %1"
exit /b
$ f
X=1 2 3 4 5
call set という遅延展開
call /?
や set /?
の説明にないため原理はよくわかっていないのですが、set の前に call を置くことで、展開を2回させることができるようです。
@echo off
setlocal
set X=1
for %%I in (2 3 4 5) do (
call set X=%%X%% %%I
)
echo X=%X%
endlocal
exit /b
$ f
X=1 2 3 4 5
call dir
などという使い方もできるため、call には eval 的な機能があるのかもしれません。