IF文で現在と指定の日時を比較・分岐してコマンドを実行するバッチファイル

指定の日、または指定の時間を越えていたらシャットダウン・再起動をするバッチファイルのメモ。

Windowsマシンのクリーンインストールやリカバリを行う機会が多く、Windows Updateを自動で繰り返すバッチファイルを走らせているのですが、一定時間放置していると更新するファイルがないのに延々と再起動を繰り返している状態があったりするので、指定の日時が来たら勝手に止まるように考えてみました。

現在を示すコマンドの参考

現在の日付を表示するコマンド

echo %DATE%

現在の時間を表示するコマンド

echo %TIME%

単純に日または時間だけで比較してコマンドを実行

日付のみで比較する場合

現在の日付が指定日またはそれ以降の日の場合、60秒後にシャットダウンします。

@echo off
set STOPDATE="2017/10/06"
if %STOPDATE% geq %DATE% shutdown /s /t 60

時間のみで比較する場合

現在の時間が指定時間以降の時間の場合、60秒後に再起動します。

@echo off
set STOPTIME="20:00:00.00"
if %STOPDATE% gtr %TIME% shutdown /r /t 60

比較演算子について

== 等しい
equ 等しい
neq 等しくない
gtr より大きい
geq 以上
leq 以下
lss より小さい(=未満)

ちなみに、/iを付けると、大文字と小文字を区別しなくなります。

日付と時間の両方で比較したいとき

コマンドプロンプトではIF文でANDやORを使って複数の条件を指定できないみたいです。

それで、IF文の中にIFにIF分を入れ子にして複数の条件を分岐させる方法もやってみたのですが、書き方が悪かったのかうまくいかなかったので、例えば、2017/10/05 22:00201710052200のように日付と時間を合体させて比較して分岐する方法でやってみました。

もっと短いコードで、いいやり方があると思いますが、とりあえずこれでもうまくいきました。

@echo off

setlocal enabledelayedexpansion

rem 終了日時を設定
set ENDDAY=2017/10/05
set ENDTIME=23:59

rem 現在の日時を数値化
Set YYYY=%Date:~0,4%
Set MM=%Date:~5,2%
Set DD=%Date:~8,2%
Set TT=%Time:~0,2%%Time:~3,2%
Set TT=%TT: =0%
Set TS=%YYYY%%MM%%DD%%TT%

rem 終了の日時を数値化
set ENDYYYY=%ENDDAY:~0,4%
Set ENDMM=%ENDDAY:~5,2%
Set ENDDD=%ENDDAY:~8,2%
Set ENDTT=%ENDTIME:~0,2%%ENDTIME:~3,2%
rem Set ENDTT=%ENDTT: =0%
Set ENDTS=%ENDYYYY%%ENDMM%%ENDDD%%ENDTT%


echo %TS%
echo %ENDTS%

if %%!TS!%% lss %%!ENDTS!%% (
	echo まだ大丈夫
) else (
	echo 終了
)

endlocal

pause

IF文の中では変数を%%!TS!%%%%!ENDTS!%%としているのは%TS%と%ENDTS%の値がECHOではちゃんと正常な数値になっているのに、IF文の条件比較では変数の値がリアルタイムに反映されていないみたいで、思ったとおりの動きになりません。

そこで、遅延環境変数(変数を!で囲って使う)というものを使います。通常、!TS!でうまくいくはずですが、思った通りに反映されなかったので、変数の値を複数回更新するという意味で%を2個付けて%%!TS!%%としています。

他のスクリプト言語だと同じ変数にどんどん値を代入すればちゃんとそのとおりの値になっているのに、バッチファイルではなりません。これはバッチファイルならではの仕様のようです。

IF文FOR文では遅延環境変数を使う癖を身に着けていないとドツボにはまりますので覚えておきたいと思います。

遅延環境変数と使うときはsetlocal enabledelayedexpansionという宣言が必要です。

setlocalの説明については省きます。ちなみにendlocalはなくても大丈夫です。