遠藤ヒズミの blog

息を吐くが如く更新が最終目標。技術からガジェット、ニチアサなどジャンルは様々

バッチファイルの変数について

はじめましてのかたは、はじめまして。ご存知の方は、そうだよヒズミさんだよ。

今回は、Windowsユーザーならおなじみ?
バッチファイルについて。
アプリの起動ファイルになってたり、定型作業の自動化によく使われるバッチファイルなんですが、 IFとかFORの構文が用意されています。コマンドを羅列するだけものじゃないんですね。
コマンドの結果を受け取る時に、FORは必要になるので、多少なれておく必要はあると思います。
しかし、まず最初に押さえておくべきは、変数の扱いかと思います。
他の言語と違って、癖があるのでその辺を書いていきます。

お品書き

  • 変数への代入
  • 変数の値の操作
  • 遅延環境変数展開

最初に言っておく!

最初に言っておく!
バッチファイルを書くくらいなら、PowerShellスクリプト書いた方が数倍楽です。
あっちも癖があって、けつまづくこともあるけど。

変数への代入

SET hoge = hoge
echo %hoge%

ほかの言語では、イコール(=)前後のスペースは有無は関係ないことが多いですね。
しかし、バッチファイルというかコマンドプロンプトの場合は、入れちゃダメっす。
そのスペースも、変数の名前になってしまいます。
つまり、echo %hoge %とすると、値が表示されます。(hogeの後ろに半角スペースが一個入ってます)
ちなみに、変数の値も、”hoge”ではなくて" hoge"と、先頭に半角スペースが入ります。 結果、hoge変数に"hoge"の値を代入したければ、下のように記述します。

REM つまり、こうすれば、おk
SET hoge=hoge
echo %hoge%

変数の値の操作

バッチファイルの変数は、基本、文字列です。 文字列の連結だけなら、変数を参照して連結したい文字を後ろにくっつけると、後ろに 文字列を連結できる。

SET char=hoge
REM 
echo %char%fuga

変数に入れたものが数字でそれを四則演算したい場合は、SETコマンドの/aを指定する。 指定せずに、他の言語のように演算記号をつけていても、文字列の連結にしかならないので、注意する。

@echo off
set num=1+1
set /a num2=1+1
echo %num%
echo %num2%

遅延環境変数展開

変数に代入できた。 そして、加算できた?
基本的には、これでおk でも、一番、ハマりやすいのが、IFやFORの中で変数を使った時です。 例えば、下のバッチスクリプトとかそうのケースです。

@echo off
set /a count=0
for /l %%i in (0,1,10) do (
    set /a count %count%+1
    echo %count%
)
 

よくあるインクリメント(1を加算する)の文ですね。 ほかの言語だと、ループするごとに、変数countの値が一つずつ増えていくと思います。 実際に、実行してみた結果がこちら

C:\Users\endoh\Dropbox\blog\cmd>noIncrement.bat
0
0
0
0
0
0
0
0
0
0
0

 

え い え ん の ゼ ロ !
なぜ、こんなことになっているのか。
それは、「FOR文は、実行時に一行になる」・「実行前に、変数を展開する」というコマンドプロンプトの挙動のせいです。
@echo onに、書き換えて、実際に流れをみてみます。

C:\Users\endoh\Dropbox\blog\cmd>noIncrement.bat

C:\Users\endoh\Dropbox\blog\cmd>set /a count=0

C:\Users\endoh\Dropbox\blog\cmd>for /L %i in (0 1 10) do (
set /a 0+1
 echo 0
)

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

C:\Users\endoh\Dropbox\blog\cmd>(
set /a 0+1
 echo 0
)
0

FOR文の実行前に、COUNT変数の値が展開されてしまうので、 ただ、ひたすら、0+1 の加算とecho 0が繰り返されるだけの悲しい結果に。
結果も格納されないので、countの値は0のままです。 期待通りにインクリメントしてもらうには、「遅延環境変数展開」というものを使います。

やり方は、 setlocalの、パラメータにenabledelayedexpansionを指定します。

@setlocal enabledelayedexpansion
@echo off
set count=0
for /l %%i in (0,1,10) do (
    set /a count=%count%+1
    echo %count%
)

参考文献