Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files

In batch I always use == when using the if command. (For example: if "19"=="3" echo My computer doesnt know maths)

What about for all of the others (LSS, LEQ, NEQ, etc.)? Isn't there something like != for NEQ, or am I thinking Unix?

The reason I want to use symbols is because I thought someone had said for either text or numbers symbols were more efficient than using the text variants.

Either way, I'd still like to know. Thanks.

like image 826
ditheredtransparency Avatar asked Nov 20 '17 05:11

ditheredtransparency


People also ask

What is NEQ in batch file?

NEQ - not equal. LSS - less than. LEQ - less than or equal. GTR - greater than. GEQ - greater than or equal.

What is %% g'in batch file?

%%parameter : A replaceable parameter: in a batch file use %%G (on the command line %G) FOR /F processing of a command consists of reading the output from the command one line at a time and then breaking the line up into individual items of data or 'tokens'.

What Is REM in Windows batch file?

REM [comment] Purpose: Provides a way to insert remarks (that will not be acted on) into a batch file. Discussion. During execution of a batch file, DOS will display (but not act on) comments which are entered on the line after the REM command. You cannot use separators in the comment except the space, tab, and comma.


2 Answers

The reason operators like > are not used is because they have special meanings in shell scripts. The > is used to redirect output; < used to redirect input, etc.

The documentation from Microsoft lists the following operators:

Operator | Description
EQU      | equal to
NEQ      | not equal to
LSS      | less than
LEQ      | less than or equal to
GTR      | greater than
GEQ      | greater than or equal to

In addition the word not is used to negate a condition.

The reason I want to use symbols is because I thought someone had said for either text or numbers symbols were more efficient than using the text variants.

They were probably referring to bash and its large catalog of operators. It provides different operators for integer and string operands.

like image 54
Burhan Khalid Avatar answered Oct 12 '22 19:10

Burhan Khalid


The internal command IF of Windows command processor has by default only two operators:

  1. == which runs a string comparison of the two arguments on equality, i.e. use lstrcmpW with condition being true on lstrcmpW returning 0.
  2. not in combination with == to invert the result of the string comparison on equality, i.e. the condition is true if the two compared strings are not equal.

So the command line

if "19"=="3" echo My computer doesn't know maths

runs lstrcmpW with the strings "19" and "3" which means the compared byte streams are hexadecimal 22 31 39 22 00 and 22 33 22 00. The double quotes are not removed before running the string comparison. The quotes are included in the string comparison.

A help for command IF is output on running in a command prompt window the command if /?. This help explains all options and additional operators which can be used on having enabled the command extensions as by default.

There is the option /I to compare the two arguments case-insensitive by using lstrcmpiW instead of lstrcmpW.

Example:

if /I not "%~1" == "/I" echo First argument is neither /i nor /I.

There are the additional comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ with enabled command extensions.

The angle brackets < and > are used on Windows command line as redirection operators. So they can't be used as comparison operators on an IF condition. The exclamation mark ! is also not available as operator because it means beginning/end of an variable reference on having enabled delayed variable expansion. Run set /? and setlocal /? and endlocal /? for details on usage of delayed variable expansion.

Windows command interpreter tries to convert both argument strings to signed 32-bit integers using wcstol with base 0 (automatic detection of base) on usage of EQU, NEQ, LSS, LEQ, GTR, GEQ. An integer comparison is done if that is successful for both argument strings because the two compared strings are

  • decimal numbers with first character being optionally - or + and all other characters are decimal digits 0123456789 with first digit not being 0 like -2147483648, -200, +10, 32, 2147483647, or
  • hexadecimal numbers with first character being optionally - or + and next with 0x or 0X and all other characters are hexadecimal digits 0123456789ABCDEFabcdef like -0x80000000, -0XC8, +0x0a, 0x20, 0x7fffFFFF, or
  • octal numbers with first character being optionally - or + and next 0 and all other characters are octal digits 01234567 like -020000000000, -0310, +012, 040, 017777777777.

Otherwise the two argument strings are compared again with lstrcmpW or with lstrcmpiW on using additionally /I with operator EQU, NEQ, LSS, LEQ, GTR, GEQ and the comparison operator is applied on the integer result of the string comparison function.

Note: 08 and 09 like other by people interpreted decimal numbers with one or more leading 0 containing 8 or 9 are interpreted as invalid octal numbers and therefore result in a string instead of an integer comparison.

The conversion of both string arguments to signed 32-bit integers needs some extra processor instructions (some nanoseconds or microseconds depending on CPU performance). An integer comparison is therefore a bit slower, but usually not really noticeable slower.

Examples:

if 014 EQU 12 echo Octal number 014 is equal decimal number 12.
if 0x0C EQU 12 echo Hexadecimal number 0C is equal decimal number 12.
if /I 0X0C EQU 014 Hexadecimal number 0C is equal octal number 014.

The option /I is ignored on using a comparison operator other than == and both strings can be converted successfully to 32-bit signed integers. This is proven by the third line above. /I is taken only into account on using the operators EQU, NEQ, LSS, LEQ, GTR, GEQ if one of the two strings cannot be converted successfully to an integer like in the following example:

if /I "0X20" EQU "0x20" echo String "0X20" is case-insensitive equal string "0x20".

If one of the two arguments is enclosed in double quotes on usage of EQU, NEQ, LSS, LEQ, GTR, GEQ, or one of the two strings is not a string representing a valid integer number, the comparison is always done with usage of lstrcmpW or lstrcmpiW depending on usage of /I. lstrcmpW and lstrcmpiW return both an integer as result which can be a negative number, zero, or a positive number. This integer result is compared with integer value 0 according to the used operator.

Examples:

if 010 NEQ "10" echo String 010 is not equal string "10".
if "100" LSS "20" echo String "100" is less than string "20".

On second example the second character 1 on left side has a lower code value (49 = 0x31) as the second character 2 on right side (50 = 0x32) which results in lstrcmpW returning a negative value resulting in function result LSS 0 being true.

Please note that Windows environment variables are always of type string and need to be converted always from string to integer on using integer comparison or integer arithmetic.

It is advisable in most cases to use string1 == string2 or not string1 == string2 instead of string1 EQU string2 or string1 NEQ string2 on comparing two strings not representing integer values to use directly lstrcmpW or lstrcmpiW. Otherwise on comparing strings with EQU or NEQ just some nanoseconds or microseconds are wasted by letting Windows command processor first use wcstol which fails to convert one of the two strings to compare and therefore cmd.exe runs next lstrcmpW or lstrcmpiW as it would be done immediately on usage of the string comparison operator ==.

One more important fact:

A string instead of an integer comparison on usage of one of the comparison operators EQU, NEQ, LSS, LEQ, GTR, GEQ is processed by cmd.exe on execution of IF condition only in case of one of the two arguments contains an invalid character. An integer comparison is done nevertheless on an out of range condition like one argument is less than -2147483648 or greater than 2147483647 as discussed at weird results with IF.

The value range limitation can be worked around by comparing two values as strings on which both value strings have the same number of characters. Here is an example to find out if a file has two or more GiB, i.e. file size is 2147483648 or more bytes.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
if "%~1" == "" ( set "FileName=%~f0" ) else set "FileName=%~1"
for %%I in ("%FileName%") do set "FileSize=000000000000000%%~zI"
if "%FileSize:~-16%" GEQ "0000002147483648" (
    echo "%FileName%" is greater or equal 2 GiB.
) else echo "%FileName%" is less than 2 GiB.
endlocal
pause

The file size of the file of which name is passed to the batch file is assigned to environment variable FileSize as string with always at least 15 additional zero digits at beginning.

And next is compared the FileSize string with just last 16 digits with string 0000002147483648 representing 2 GiB in bytes. lstrcmpW compares the two strings of equal length byte by byte whereby each byte of the two compared strings within the also compared double can have only the hexadecimal values 0x30 to 0x39. lstrcmpW returns immediately with a negative value if the current byte from left string is less than the current byte from right string which means the file size is less than 2 GiB. lstrcmpW returns immediately with a positive value if the current byte from left string is greater than the current byte from right string which means the file size is greater than 2 GiB. lstrcmpW returns with zero on the two strings are 100% identical which means the file size is exactly 2 GiB.

Please note that comparing values using a string comparison requires that both values have the same number of characters for an accurate result. The value string with less digits must be prepended with the right amount of 0.

like image 27
Mofi Avatar answered Oct 12 '22 19:10

Mofi