I recommend reading How does the Windows Command Interpreter (CMD.EXE) parse scripts?
Windows command processor replaces all environment variable references using syntax %variable%
inside a command block starting with (
and ending with matching )
already on parsing the command line using this command block. This means the command line echo %difference%
inside ELSE branch command block of the IF command is modified by cmd.exe
before command IF is executed at all. %difference%
is replaced by current value of environment variable difference
or an empty string in case of environment variable difference
is not defined somewhere above the IF condition. In latter case echo
is the command line remaining after parsing the command block and therefore shows status of command echoing instead of the string value assigned to environment variable difference
in the command line above. The solution with already enabled delayed environment variable expansion is using echo !difference!
in ELSE command block.
A solution for this floating point subtraction without usage of PowerShell can be seen below:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
if defined NewValue goto Validate
:UserPrompt
set /P "NewValue=Enter value between 00.0 and 99.9: "
:Validate
echo:!NewValue!| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]\.[0123456789]$" >nul
if errorlevel 1 set "NewValue=" & goto UserPrompt
for /F "tokens=1,2 delims=." %%I in ("%NewValue%") do set "PreComma=%%I" & set "PostComma=%%J"
set /A Difference=1%PreComma% - 112
set "Difference=%Difference%.%PostComma%"
echo Difference is: %Difference%
endlocal
After validating that the string assigned to environment variable NewValue
indeed consists of two digits, a point and one more digit as requested and expected and described at How can I do a negative regex match in batch?, the floating point number string is split up on .
into pre-comma and post-comma number strings.
The pre-comma number is subtracted by 12 using an arithmetic expression. But it must be taken into account that an integer number with a leading 0 is interpreted by cmd.exe
on evaluation of the arithmetic expression as octal number. That is no problem for 00
to 07
. But 08
and 09
would be invalid octal numbers and so Windows command processor would use value 0
resulting in a wrong subtraction result if simply set /A Difference=PreComma - 12
would have been used in batch file. The workaround is concatenating the string 1
with the pre-comma string to a number string in range 100
to 199
and subtract 112
to get the correct result.
The post-comma value does not need to be modified and so the Difference
value is determined finally with concatenating the result of the arithmetic expression with the unmodified post-comma number string.
It is possible to get the Difference
value also always with two digits by inserting following additional command lines above echo Difference is: %Difference%
:
if %Difference:~0,1% == - (
if %Difference:~2,1% == . set "Difference=-0%Difference:~1%"
) else (
if %Difference:~1,1% == . set "Difference=0%Difference%"
)
This solution avoids also the problem that floating point result of PowerShell
is formatted according to region and language settings. For example in Germany and Austria the decimal symbol is ,
and not .
which means the subtraction result output by PowerShell for 15.3 - 12.0
is 3,3
and not 3.3
.
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 /?
endlocal /?
findstr /?
for /?
goto /?
if /?
set /?
setlocal /?
See also single line with multiple commands using Windows batch file.