Windows batch files: Strange behavior of the IF command

Windows[German]German blog reader Frank contacted me about a problem on Windows that I don't really have an explanation for. Originally it was about the IF command in batch files returning wrong values when comparing. So Frank tested the whole thing with PowerShell and found something similar there. Only a test program written with VB .NET delivered the expected results. Since the batch program also delivers the same, incorrect, results under Windows 7, I assume that Frank and I have overlooked something. I'll post the problem here in the blog – maybe a reader will notice something.


Advertising

Problem: Incorrect batch evaluation

German blog reader Frank S. recently contacted me by e-mail and wrote me about his problem in using the IF command with batch files. Frank wrote:

I keep stumbling across strange things in windows. Today I wanted to implement a batch program where I have to compare letters on "greater than" or "less than". This can involve lowercase letters as well as uppercase letters.

The program behaved completely absurdly, so I got to the bottom of it and finally realized that the "if" command with the extended compare commands behaves as if I used the "/I" option, which I did not. I have created a small example program here that shows the strange behavior.

Frank provided me with the following source code of the batch script.


@echo off
setlocal enableextensions
if A == a (
echo A == a : True [Wrong!]
) else (
echo A == a : False [OK]
)
if A EQU a (
echo A EQU a : True [Wrong!]
) else (
echo A EQU a : False [OK]
)
if A LSS b (
echo A LSS b : True [OK]
) else (
echo A LSS b : False [Wrong!]
)
if A LEQ b (
echo A LEQ b : True [OK]
) else (
echo A LEQ b : False [Wrong!]
)
if A GTR b (
echo A GTR b : True [Wrong!]
) else (
echo A GTR b : False [OK]
)
if A GEQ b (
echo A GEQ b : True [Wrong!]
) else (
echo A GEQ b : False [OK]
)
if a LSS B (
echo a LSS B : True [Wrong!]
) else (
echo a LSS B : False [OK]
)
if a LEQ B (
echo a LEQ B : True [Wrong!]
) else (
echo a LEQ B : False [OK]
)
if a GTR B (
echo a GTR B : True [OK]
) else (
echo a GTR B : False [Wrong!]
)
if a GEQ B (
echo a GEQ B : True [OK]
) else (
echo a GEQ B : False [Wrong!]
)
if Z LSS a (
echo Z LSS a : True [OK]
) else (
echo Z LSS a : False [Wrong!]
)
if ALPHA LSS alpha (
echo ALPHA LSS alpha : True [OK]
) else (
echo ALPHA LSS alpha : False [Wrong!]
)
if ALPHA LEQ alpha (
echo ALPHA LEQ alpha : True [OK]
) else (
echo ALPHA LEQ alpha : False [Wrong!]
)
if ALPHA GTR alpha (
echo ALPHA GTR alpha : True [Wrong!]
) else (
echo ALPHA GTR alpha : False [OK]
)
if ALPHA GEQ alpha (
echo ALPHA GEQ alpha : True [Wrong!]
) else (
echo ALPHA GEQ alpha : False [OK]
)
Pause

Frank wrote that he ran this batch file on Windows 10 with the latest patch level (V10.0.19044.2006) and got the following output.


A == a : False [OK]
A EQU a : False [OK]
A LSS b : True [OK]
A LEQ b : True [OK]
A GTR b : False [OK]
A GEQ b : False [OK]
a LSS B : True [Wrong!]
a LEQ B : True [Wrong!]
a GTR B : False [Wrong!]
a GEQ B : False [Wrong!]
Z LSS a : False [Wrong!]
ALPHA LSS alpha : False [Wrong!]
ALPHA LEQ alpha : False [Wrong!]
ALPHA GTR alpha : True [Wrong!]
ALPHA GEQ alpha : True [Wrong!]

The Extended comparisons ignore upper or lower case. The character a is numerically greater than a B or an A in ANSI and Unicode. Frank writes that the commands behave as if the /I option had been specified. However, it is unclear why ALPHA GTR alpha gives the result True. Only the comparisons == and EQU behave correctly.

IF-Vergleich


Advertising

I ran the whole thing on Windows 7 SP1 and get the same result – so it doesn't depend on Windows 10. There must be some kind of thinking error. Frank wrote me in response to the question about a thinking error:

That was also my first thought. But I can't find anything. I have now tested the whole thing with 3 different programming languages:

1. Batch
2. PowerShell
3. VB .NET

The two scripting languages both give the same wrong result. So it is not a problem of Batch alone. VB .NET does it right.

Here are the source codes of the test programs in question, which write the results to an output window with an encoding for CodePage850.

Batch program

@echo off

setlocal enableextensions enabledelayedexpansion

set alphabet=0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜäöüß

set pos=0

:mainLoop

set char=!alphabet:~%pos%,1!

if A%char% == A goto :endProc

echo.

set pos2=0

:innerLoop

set char2=!alphabet:~%pos2%,1!

if A%char2% == A goto :nextMain

call :testChar %char% %char2%

set /a pos2=pos2+1

goto :innerLoop

:nextMain

set /a pos=pos+1

goto :mainLoop

:testChar

if %1 lss %2 echo %1 ^<  %2

if %1 leq %2 echo %1 ^<= %2

if %1 gtr %2 echo %1 ^>  %2

if %1 geq %2 echo %1 ^>= %2

exit /b

:endProc

PowerShell script

function Test-Char

{

Param

(

[Parameter(Mandatory=$true, Position=0)]

[string] $Char1,

[Parameter(Mandatory=$true, Position=1)]

[string] $Char2

)

if ($Char1 -clt $Char2) {

Write-Output "$Char1 <  $Char2"

}

if ($Char1 -cle $Char2) {

Write-Output "$Char1 <= $Char2"

}

if ($Char1 -cgt $Char2) {

Write-Output "$Char1 >  $Char2"

}

if ($Char1 -cge $Char2) {

Write-Output "$Char1 >= $Char2"

}

}

$PSDefaultParameterValues['Out-File:Encoding'] = 'oem'

$alphabet="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜäöüß"

for($pos1=0; $pos1 -lt $alphabet.Length; $pos1++) {

Write-Output ""

for($pos2=0; $pos2 -lt $alphabet.Length; $pos2++) {

Test-Char $alphabet.Substring($pos1, 1) $alphabet.Substring($pos2, 1)

}

}


VB .NET


Imports System
Module Program
Sub Main(args As String())
Dim alphabet As String = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜäöüß"
For pos1 As Integer = 0 To alphabet.Length - 1
Console.WriteLine()
For pos2 As Integer = 0 To alphabet.Length - 1
TestChar(alphabet.Substring(pos1, 1), alphabet.Substring(pos2, 1))
Next pos2
Next pos1
End Sub
Private Sub TestChar(char1 As String, char2 As String)
If char1 < char2 Then _
Console.WriteLine($"{char1} <  {char2}")
If char1 <= char2 Then _
Console.WriteLine($"{char1} <= {char2}") If char1 > char2 Then _
Console.WriteLine($"{char1} >  {char2}")
If char1 >= char2 Then _
Console.WriteLine($"{char1} >= {char2}")
End Sub
End Module

Therefore, I would like to ask the readers if anyone can think of an ad hoc explanation for this. First reactions within my German blog, people are puzzled about that issue.


Cookies helps to fund this blog: Cookie settings
Advertising


This entry was posted in Windows and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *