Jaroslaw Pawlak
Jaroslaw Pawlak

Reputation: 5578

can't get variable value in the if statement in windows batch file

I am trying to write a simple batch file which will control access to the computer (using shutdown) so for every 30 minutes when the computer is on, there has to be at least 30 minutes when the computer is off. The file will be put in auto start. The algorithm looks as follows:

Get from the file time when the computer was last closed (LASTCLOSETIME)
calculate BREAKUNTIL as LASTCLOSETIME + 30 minutes
if CURRENTTIME < BREAKUNTIL {
    then shutdown now
} else {
    shutdown in 30 minutes
    save to the file CURRENTTIME + 30 minutes
}

I did not handle what happens in the first run if the file does not exist, but it is not a problem for now - a file exists and contains valid data.

The code I have:

::echo off

FOR /F "DELIMS=" %%G IN ('TIME /T') DO SET CURRENTTIME=%%G
echo %CURRENTTIME%

set /A CURRENTTIME = %CURRENTTIME:~0,2%*60 + %CURRENTTIME:~3,2%
echo %CURRENTTIME%

set /P LASTCLOSETIME=<lastclose.txt

set /A BREAKUNTIL = %LASTCLOSETIME% + 30
set /A BREAKUNTIL = %BREAKUNTIL% %% 1440

echo CURRENTTIME: %CURRENTTIME%
echo LASTCLOSETIME: %LASTCLOSETIME%
echo BREAKUNTIL: %BREAKUNTIL%

if "%CURRENTTIME%" LSS "%BREAKUNTIL%" (
    shutdown -s -t 30
) else (
    shutdown -s -t 1800

    set CLOSETIME = %CURRENTTIME%
    echo CLOSETIME: %CLOSETIME%
    set /A CLOSETIME = %CLOSETIME% + 30
    set /A CLOSETIME = %CLOSETIME% %% 1440

    echo %CLOSETIME%
    echo %CLOSETIME% > lastclose.txt
)

PAUSE

The problem is where I set CLOSETIME. It successfully gets the value of CURRENTTIME and I can see e.g. "set CLOSETIME = 886" in the console but the next line does not print this time at all, as if a variable was not set. Does it have something to do with the if statement? I have tried using labels and goto statements but the result was the same.

Upvotes: 0

Views: 1488

Answers (1)

Magoo
Magoo

Reputation: 79983

Standard DELAYEDEXPANSION problem.

This is ONE compound statement:

if "%CURRENTTIME%" LSS "%BREAKUNTIL%" (
    shutdown -s -t 30
) else (
    shutdown -s -t 1800

    set CLOSETIME = %CURRENTTIME%
    echo CLOSETIME: %CLOSETIME%
    set /A CLOSETIME = %CLOSETIME% + 30
    set /A CLOSETIME = %CLOSETIME% %% 1440

    echo %CLOSETIME%
    echo %CLOSETIME% > lastclose.txt
)

When the statement is PARSED, the CURRENT values of any %var% are substituted and THEN the statement is executed. The value isn't ASSIGNED to closetime until the statement is EXECUTED, hence the statement is interpreted as

if "%CURRENTTIME%" LSS "%BREAKUNTIL%" (
    shutdown -s -t 30
) else (
    shutdown -s -t 1800

    set CLOSETIME = %CURRENTTIME%
    echo CLOSETIME: 
    set /A CLOSETIME = + 30
    set /A CLOSETIME =  %% 1440

    echo 
    echo  > lastclose.txt
)

Easiest cure is to change this sequence to

if "%CURRENTTIME%" LSS "%BREAKUNTIL%" (
    shutdown -s -t 30
    GOTO :EOF
)
shutdown -s -t 1800

set CLOSETIME = %CURRENTTIME%
echo CLOSETIME: %CLOSETIME%
set /A CLOSETIME = %CLOSETIME% + 30
set /A CLOSETIME = %CLOSETIME% %% 1440

echo %CLOSETIME%
echo %CLOSETIME% > lastclose.txt

Note that GOTO :EOF where the colon is required means 'go to the physical end-of-file.

Second easiest is to execute

SETLOCAL ENABLEDELAYEDEXPANSION

somewhere before this IF statement (commonly directly after the @echo off) and change the IF to

if "%CURRENTTIME%" LSS "%BREAKUNTIL%" (
    shutdown -s -t 30
) else (
    shutdown -s -t 1800

    set CLOSETIME = %CURRENTTIME%
    echo CLOSETIME: !CLOSETIME!
    set /A CLOSETIME = !CLOSETIME! + 30
    set /A CLOSETIME = !CLOSETIME! %% 1440

    echo !CLOSETIME!
    echo !CLOSETIME! > lastclose.txt
)

Noting that when DELAYEDEXPANSION is in effect, !var! returns the RUNTIME value of var (ie as it changes) whereas %var% returns the PARSE-TIME value of var (ie as it stood when the statement was parsed, before execution.)

Upvotes: 1

Related Questions