Batch file comparison of variable with constant fails

1. Debugging a batch file

For debugging a batch file to find syntax errors in code it is recommended to run the batch file from within a command prompt window after having each echo off modified to echo ON or removed from batch file or commented out with command REM.

By default Windows command interpreter outputs each command line or an entire command block starting with ( and ending with matching ) after parsing and preprocessing on which environment variables referenced with %variable% (immediate expansion) are already replaced by current value of the environment variable before executing the command line / block.

This default behavior is turned off with @echo off at top of the batch file whereby @ at beginning of the command line disables also output of this first command line. That is of course welcome when the development of the batch file is finished and the batch file is working fine. But for debugging a batch file not working as expected it is better to see also the command lines really executed by command interpreter to find out where the batch file execution is exited unexpected because of an error.

The ECHO behavior is explained very briefly in help output on running echo /? from within a command prompt window.

Opening a command prompt window results in starting cmd.exe implicitly with option /K to keep the command process running and the console window open after execution of a batch file or application finished.

An exception is when the batch file contains the command exit without parameter /B because in this case the current command process is always exited independent on calling hierarchy. exit /B is equal goto :EOF and should be used instead of just exit, except there is a really good reason for using just exit. exit /B and goto :EOF require both command extensions as enabled by default on Windows.

Double clicking on a batch file results in starting cmd.exe with option /C to close command process and its console window automatically when execution of the application or batch file is finished independent on the reason why the execution of a batch file terminated. This behavior with closing automatically the console window is not good for debugging a batch file because the error message can’t be seen when batch file execution terminated because of a syntax error.

For more details about options of Windows command interpreter run in a command prompt window the command: cmd /?

How to exit intentionally the execution of a batch file using goto :EOF (colon is here important by way of exception) or exit /B (just an internal alias for goto :EOF) is explained in help of those two commands displayed by running goto /? and exit /? in a command prompt window.

For debugging a larger batch file it could be helpful to use a temporarily added goto at top of the batch file to jump to a certain block and a goto :EOF to exit batch processing after the block to debug.

By the way: :: is an invalid label often used for comments in batch files as label lines are never displayed on execution of a batch file. But in the command block of a FOR loop labels can’t be used because Windows command interpreter fails to interpret right a FOR loop with labels inside the command block. For that reason it is better to use command REM (remark) for comments as this command is designed for comments in batch files and really work anywhere in a batch file.

See also How can I debug a .BAT script?

2. Error in batch file

On running the batch file posted in question with both @ECHO OFF commented out by replacing it with rem @echo off (run a replace in text editor) from within a command prompt window it can be seen easily on which line the error occurs:

if %DiffSec% LSS 10 (ECHO "LESS 10")else %DiffSec% LSS 1 (ECHO "LESS 1")

If current value of environment variable DiffSec is not lower than 10 then the ELSE branch is executed by Windows command interpreter which starts with the number like 10.

Windows command interpreter can’t find an application with that name in current directory or any directory specified in semicolon separated directory list of environment variable PATH having a file extension specified in semicolon separated file extension list of environment variable PATHEXT.

The mistake is here obviously the missing IF command for the next comparison. So the correct code would be

if %DiffSec% LSS 10 (ECHO "LESS 10") else if %DiffSec% LSS 1 ECHO "LESS 1"

This would be easier to read on writing the condition on multiple lines:

if %DiffSec% LSS 10 (
    ECHO "LESS 10"
) else if %DiffSec% LSS 1 (
    ECHO "LESS 1"
)

The syntax is now correct.

But the second condition does not make sense as JosefZ mentioned already in his comment. If value of DiffSec is 10 or greater resulting in execution of the IF command in ELSE branch, this condition is definitely also never true. So more sense would make:

if %DiffSec% LSS 1 (ECHO LESS 1) else if %DiffSec% LSS 10 ECHO LESS 10

Or alternatively

if %DiffSec% LSS 1 (
    ECHO LESS 1
) else if %DiffSec% LSS 10 (
    ECHO LESS 10
)

For more information about valid IF ELSE conditions in batch files see for example the answers on

3. Add leading zero for numbers < 10

Environment variables are always of type string. For arithmetic expressions the string value of an environment variable is converted to a signed 32-bit integer if possible at all and the result of the arithmetic expression is converted back from signed 32-bit integer to string.

Also an IF condition like if %DiffSec% LSS 10 being expanded before execution for example to if 5 LSS 10 results in converting 5 (0x35) from string to integer and 10 (0x31 0x30) also from string to integer for comparing the two numbers as integers.

So it would be a bit faster to avoid such a number comparison if that is possible.

It is quite easy to add a leading zero to a number lower than 10 without really testing on value by using string substitution.

First the current value of the environment variable is prepended with one (for a two digits number) or more 0 (for 3, 4 or even more digits).

set "DiffSec=0%DiffSec%"

Next the last X characters like 2 for a two digit number are assigned from current value of environment variable to the environment variable.

set "DiffSec=%DiffSec:~-2%"

String substitution is explained in help of command SET output by running in a command prompt window set /?.

The result of the two lines is that DiffSec has for values 0 to 99 after those two lines always a two digit number in range 00 to 99.

4. Parsing of an arithmetic expression

An arithmetic expression which is the string after set /a is interpreted by Windows command interpreter completely different than other strings.

Spaces and tabs are word separators, but have no further special meaning. Therefore it is advisable to use spaces to make the arithmetic expression better readable.

Then there are a lot of operators which are listed in help of command SET displayed on running in a command prompt window set /?.

Further decimal, octal and hexadecimal integers are interpreted in an arithmetic expression as integers.

And last every other string is interpreted as name of an environment variable of which current value is converted from string to integer.

For that reason it is not advisable to use immediate or delayed expansion in an arithmetic expression.

Referencing value of an environment variable with %variable% within an arithmetic expression is not good when used within a command block on which the current value of the environment variable replaces the variable reference already on parsing the entire command block before executing the first command.

Referencing value of an environment variable with !variable! within an arithmetic expression is also not good because it requires enabling delayed expansion which results in handling exclamation marks in strings not anymore as literal characters.

So best is always simply writing the variable names in an arithmetic expression without surrounding percent signs or exclamation marks if that is possible because of variable name does not contain a space character and starting with a character which can’t be interpreted as integer character by Windows command interpreter.

See also answer on Why is no string output with ‘echo %var%’ after using ‘set var = text’ on command line? for details on how to assign a value to an environment variable using just set or set /P (prompt) or set /A (arithmetic expression).

5. Fixed and optimized code

The code in question can be fixed and optimized to this code:

@echo off
rem Time Calculation
for /F "skip=1 tokens=1-4" %%A in ('%SystemRoot%\System32\wbem\wmic.exe PATH Win32_LocalTime GET Day^,Hour^,Minute^,Second') do (
    set Day=%%A
    set Hour=%%B
    set Minute=%%C
    set Second=%%D
)
set /A TimeStart=Day * 86400 + Hour * 3600 + Minute *60 + Second

@echo on
%SystemRoot%\System32\ping.exe 8.8.8.8 -n 11
@echo off

for /F "skip=1 tokens=1-4" %%A in ('%SystemRoot%\System32\wbem\wmic.exe PATH Win32_LocalTime GET Day^,Hour^,Minute^,Second') do (
    set Day=%%A
    set Hour=%%B
    set Minute=%%C
    set Second=%%D
)
set /A TimeEnd=Day * 86400 + Hour * 3600 + Minute *60 + Second

set /A TimeDiff=TimeEnd - TimeStart
set /A DiffSec=TimeDiff %% 60
set /A TimeDiff=(TimeDiff - DiffSec) / 60
set /A DiffMin= TimeDiff %% 60
set /A DiffHrs=(TimeDiff - DiffMin) / 60

set "DiffSec=0%DiffSec%"
set "DiffSec=%DiffSec:~-2%"
set "DiffMin=0%DiffMin%"
set "DiffMin=%DiffMin:~-2%"
set "DiffHrs=0%DiffHrs%"
set "DiffHrs=%DiffHrs:~-2%"

echo Time needed for orders deletion: %DiffHrs%:%DiffMin%:%DiffSec%

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • echo /?
  • for /?
  • ping /?
  • rem /?
  • set /?
  • wmic /?
  • wmic path /?

Leave a Comment