バッチファイルを作成するにあたり、for文の中で変数を定義するようなコードを書くことがある。
for文の中にfor文を記述するような、2重ループなどが該当する。
その際、例えば以下のようなソースを書くとしよう。
@Echo off
Set LIST=%~f1
For /f "delims=," %%a In (%LIST%) Do (
Set LINE=%%a
Echo "LINE>%LINE%"
)
で、以下のような外部ファイルを読みこませようとするとしよう。
aaaaa
bbbbb
ccccc
ddddd
eeeee
fffff
ggggg
hhhhh
このとき、意図した動きは以下のような表示がされる事になると思う。
"LINE>aaaaa"
"LINE>bbbbb"
"LINE>ccccc"
"LINE>ddddd"
"LINE>eeeee"
"LINE>fffff"
"LINE>ggggg"
"LINE>hhhhh"
ところが、実際に実行すると以下のように表示されてしまう。
"LINE>hhhhh"
"LINE>hhhhh"
"LINE>hhhhh"
"LINE>hhhhh"
"LINE>hhhhh"
"LINE>hhhhh"
"LINE>hhhhh"
"LINE>hhhhh"
これは…表示される行数は一緒だけども、中身が全て最後の行(最終行)の値になってしまっている。
なんでだろう?
以下に記載するブログに詳細な理由と対処法が記述されていたので、紹介する。
FOR文やIF文で変数の中身が消える? (DOSの変数の代入)
遅延展開される CMD バッチスクリプトで ! を記述する方法
このような構文を作成する場合、バッチの遅延環境変数の展開を利用する必要がある。
以下の一文をバッチファイルに追記し、遅延展開する変数の記述方法を「%変数名%」から「!変数名!」に変更する必要がある。
setlocal enabledelayedexpansion
今回例に出したバッチの場合は、以下のように記述する。
@Echo off
setlocal enabledelayedexpansion
Set LIST=%~f1
For /f "delims=," %%a In (%LIST%) Do (
Set LINE=%%a
Echo "LINE>!LINE!"
)
2行目(というか、「@Echo off」の直後)に「setlocal enabledelayedexpansion」を記述。
そして、6行目の変数「LINE」の記述方法を変えているのがわかると思う。
このバッチを実行した結果が以下。
"LINE>aaaaa"
"LINE>bbbbb"
"LINE>ccccc"
"LINE>ddddd"
"LINE>eeeee"
"LINE>fffff"
"LINE>ggggg"
"LINE>hhhhh"
以上。
なお、久しぶりに遅延展開が必要なバッチを作成していて、書き方はおろかなんの機能使うのかすら忘れて1時間くらい迷走していたのは内緒だ!