【Windowsバッチ・DOS】バッチファイルの環境変数スコープあれこれ

Windowsユーザーならみんなbatファイル好きだよね。 一度ははまるであろう環境変数のスコープについてあれこれをまとめる。

setコマンド

set 一時環境変数名=値

環境変数を一時設定する。 実行したコマンドプロンプト内でのみ有効。 (他のプロセスからは見えない。該当プロセスから立ち上がった子プロセスはスコープを引き継ぐ。コマンドプロンプト落とすと消える。)

ちなみに、ユーザー環境変数とかシステム環境変数といったものを恒久的に変えたければsetxコマンドを使うそうだ。

setlocalとendlocal

「バッチの中だけでスコープ切りたい!」ってときに使えるコマンド。

set X=outscope

setlocal

echo %X%
rem outscopeと表示される


set X=inscope

echo %X%
rem inscopeと表示される


endlocal

echo %X%
rem outscopeと表示される

pause

ブロック内で環境変数更新

皆がはまったであろう罠。

例えば、forで複数命令実行するときは( ... )で囲んでブロック化する。

for %%i in ( * ) do (
  set FILENAME=%%i
  echo ファイル名は「%FILENAME%」です
)

ところが、上のようにブロック内で環境変数を使った場合、コマンド実行時にfor~ブロック終わりの)までが一度評価されて、以下のように展開される。

for %%i in ( * ) do (
  set FILENAME=%%i
  echo ファイル名は「」です
)

むごい。

回避方法

回避方法を2つ紹介。

setlocal enabledelayedexpansion

setlocal enabledelayedexpansionと宣言すれば、遅延環境変数というものが使える。

setlocal enabledelayedexpansion
for %%i in ( * ) do (
  set FILENAME=%%i
  echo ファイル名は「!FILENAME!」です
)

サブルーチン化

callで別処理に呼ぶと回避できる。

for %%i in ( * ) do (
  call :PRINTNAME %%i
)

goto :END

:PRINTNAME
echo ファイル名は「%1」です
exit /b

:END

pause