311

How would you implement logical operators in DOS Batch files?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
JoelFan
  • 37,465
  • 35
  • 132
  • 205

14 Answers14

366

You can do and with nested conditions:

if %age% geq 2 (
    if %age% leq 12 (
        set class=child
    )
)

You can also do this in a short form:

if %age% geq 2 if %age% leq 12 set class=child

You can do or with a separate variable:

set res=F
if %hour% leq 6 set res=T
if %hour% geq 22 set res=T
if "%res%"=="T" (
    set state=asleep
)

Note that this answer is tailored toward cmd batch language, the one found in Windows. You mention "DOS batch" but, based on several points, I think the former choice is a safe bet(1).

If you really meant the original MS-DOS batch language, you should keep in mind that the if statement was a lot simpler, and you may need to use chunks of if ... goto for control flow, rather than (for example) parentheses or else.


(1) Supported by the following points:

  • The presence of the cmd and windows-console tags;
  • Prior experience of some people failing to recognise the very real difference between cmd and MS-DOS batch languages, and conflating DOC with the cmd terminal window;
  • The question using the more generic "DOS" rather than specifically "MS-DOS" (where "DOS" could possibly be any disk operating system;
  • The fact this is Stack Overflow rather than the retro-computing sister site, where a question about MS-DOS would be way more appropriate (I'm often on that site as well, it's nice for those of us who remember and appreciate computer history); and
  • The (eventual) acceptance of the answer by the original asker, indicating that the solution worked.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 18
    You can also just use `set res=` or `set res=1` and then `if defined res` which is a little more robust against typos and works even in blocks without explicitly enabling delayed expansion. – Joey Jan 26 '10 at 23:34
  • 7
    Just to improve your answer a bit... you don't need to explicitly nest the "if" statements... you can just "chain" them, as Dave Jarvis demonstrates below – JoelFan Jan 28 '10 at 14:44
  • Befare not to leave any spaces after the set=true or the thing just gracefully does not work. It would store value "true " in the variable... – Roland Pihlakas Aug 29 '15 at 21:19
  • 1
    The 'or' condition you describe is slick and works great for a range of numbers, but what if I am comparing 2 independent values, and not a range? For example, if this file exists or filename == "" – bakoyaro Dec 14 '17 at 21:10
  • 1
    @bakoyaro, you can use any condition to set res to true, including the ones you mention. – paxdiablo Dec 14 '17 at 21:33
  • this doesn't work in MS-DOS. `if cond () else ()` is cmd-only – phuclv Aug 09 '22 at 13:46
  • @phuclv: The presence of the `cmd` and "windows console" tag, the continuing inability of some people here to recognise a difference between `cmd` and "DOS batch", the fact that it states "DOS rather than "MSDOS", the fact this is SO rather than retro-computing, and the answer being accepted by the OP, all seem to indicate the inability to run under MSDOS is ... not really an issue :-) But I'll clarify. – paxdiablo Aug 09 '22 at 21:17
88

The IF statement does not support logical operators AND and OR. Cascading IF statements make an implicit conjunction:

IF Exist File1.Dat IF Exist File2.Dat GOTO FILE12_EXIST_LABEL

If File1.Dat and File2.Dat exist then jump to the label FILE12_EXIST_LABEL.

See also: IF /?

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
66

De Morgan's laws allow us to convert disjunctions ("OR") into logical equivalents using only conjunctions ("AND") and negations ("NOT"). This means we can chain disjunctions ("OR") on to one line.

This means if name is "Yakko" or "Wakko" or "Dot", then echo "Warner brother or sister".

set warner=true
if not "%name%"=="Yakko" if not "%name%"=="Wakko" if not "%name%"=="Dot" set warner=false
if "%warner%"=="true" echo Warner brother or sister

This is another version of paxdiablo's "OR" example, but the conditions are chained on to one line. (Note that the opposite of leq is gtr, and the opposite of geq is lss.)

set res=true
if %hour% gtr 6 if %hour% lss 22 set res=false
if "%res%"=="true" set state=asleep
anomal
  • 2,249
  • 2
  • 19
  • 17
8

OR is slightly tricky, but not overly so. Here is an example

set var1=%~1
set var2=%~2
::
set or_=
if "%var1%"=="Stack" set or_=true
if "%var2%"=="Overflow" set or_=true
if defined or_ echo Stack OR Overflow
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Timo Salmi
  • 254
  • 3
  • 3
  • Does not work. If I give it Stack, it echoes. If I give it Overflow, it does not - it should. – Unknow0059 Dec 03 '20 at 03:32
  • 1
    @Unknow0059: it echoes if the first argument is Stack or the second argument is Overflow. I suspect that may have been a mistake by Timo (should have just used `var1` but it doesn't mean the concept doesn't work. – paxdiablo Aug 09 '22 at 21:39
6

The following examples show how to make an AND statement (used for setting variables or including parameters for a command).

To start Notepad and close the CMD window:

start notepad.exe & exit

To set variables x, y, and z to values if the variable 'a' equals blah.

IF "%a%"=="blah" (set x=1) & (set y=2) & (set z=3)

Hope that helps!

Stephan
  • 53,940
  • 10
  • 58
  • 91
GinDiamond
  • 61
  • 1
  • 1
3

If you have interested to write an if+AND/OR in one statement, then there is no any of it. But, you can still group if with &&/|| and (/) statements to achieve that you want in one line w/o any additional variables and w/o if-else block duplication (single echo command for TRUE and FALSE code sections):

@echo off
    
setlocal
    
set "A=1" & set "B=2" & call :IF_AND
set "A=1" & set "B=3" & call :IF_AND
set "A=2" & set "B=2" & call :IF_AND
set "A=2" & set "B=3" & call :IF_AND
    
echo.
    
set "A=1" & set "B=2" & call :IF_OR
set "A=1" & set "B=3" & call :IF_OR
set "A=2" & set "B=2" & call :IF_OR
set "A=2" & set "B=3" & call :IF_OR
    
exit /b 0
    
:IF_OR
( ( if %A% EQU 1 ( type nul>nul ) else type 2>nul ) || ( if %B% EQU 2 ( type nul>nul ) else type 2>nul ) || ( echo.FALSE-& type 2>nul ) ) && echo TRUE+
    
exit /b 0
    
:IF_AND
( ( if %A% EQU 1 ( type nul>nul ) else type 2>nul ) && ( if %B% EQU 2 ( type nul>nul ) else type 2>nul ) && echo.TRUE+ ) || echo.FALSE-

    
exit /b 0

More uniform version:

@echo off

setlocal

set "A=1" & set "B=2" & ( call :IF_AND "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-
set "A=1" & set "B=3" & ( call :IF_AND "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-
set "A=2" & set "B=2" & ( call :IF_AND "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-
set "A=2" & set "B=3" & ( call :IF_AND "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-

echo.

set "A=1" & set "B=2" & ( call :IF_OR "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-
set "A=1" & set "B=3" & ( call :IF_OR "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-
set "A=2" & set "B=2" & ( call :IF_OR "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-
set "A=2" & set "B=3" & ( call :IF_OR "%%A%% EQU 1" "%%B%% EQU 2" && echo TRUE+ ) || echo FALSE-

exit /b 0

:IF_OR
if %~1 ( exit /b 0 ) else if %~2 ( exit /b 0 ) else exit /b 1
exit /b -1

:IF_AND
if %~1 ( if %~2 ( exit /b 0 ) else exit /b 1 ) else exit /b 1
exit /b -1

Output:

TRUE+
FALSE-
FALSE-
FALSE-
    
TRUE+
TRUE+
TRUE+
FALSE-

The trick is in the type command which drops/sets the errorlevel and so handles the way to the next command.

Andry
  • 2,273
  • 29
  • 28
2

Athul Prakash (age 16 at the time) gave a logical idea for how to implement an OR test by negating the conditions in IF statements and then using the ELSE clause as the location to put the code that requires execution. I thought to myself that there are however two else clauses usually needed since he is suggesting using two IF statements, and so the executed code needs to be written twice. However, if a GOTO is used to skip past the required code, instead of writing ELSE clauses the code for execution only needs to be written once.

Here is a testable example of how I would implement Athul Prakash's negative logic to create an OR.

In my example, someone is allowed to drive a tank if they have a tank licence OR they are doing their military service. Enter true or false at the two prompts and you will be able to see whether the logic allows you to drive a tank.

@ECHO OFF
@SET /p tanklicence=tanklicence:
@SET /p militaryservice=militaryservice:

IF /I NOT %tanklicence%==true IF /I NOT %militaryservice%==true GOTO done

ECHO I am driving a tank with tanklicence set to %tanklicence% and militaryservice set to %militaryservice%

:done

PAUSE
Ivan
  • 4,383
  • 36
  • 27
2

It's just as easy as the following:

AND> if+if

if "%VAR1%"=="VALUE" if "%VAR2%"=="VALUE" *do something*

OR> if // if

set BOTH=0
if "%VAR1%"=="VALUE" if "%VAR2%"=="VALUE" set BOTH=1
if "%BOTH%"=="0" if "%VAR1%"=="VALUE" *do something*
if "%BOTH%"=="0" if "%VAR2%"=="VALUE" *do something*

I know that there are other answers, but I think that the mine is more simple, so more easy to understand. Hope this helps you! ;)

Renk Software
  • 144
  • 2
  • 10
2

A lot of people seem to be missing the most obvious solution for OR which is to use a label.

if "%a%" == "ONE" goto do_thing
if "%a%" == "TWO" (
   :do_thing
   echo a is equal to ONE or TWO
)
Sollace
  • 668
  • 8
  • 12
1

Try the negation operand - 'not'!

Well, if you can perform 'AND' operation on an if statement using nested 'if's (refer previous answers), then you can do the same thing with 'if not' to perform an 'or' operation.

If you haven't got the idea quite as yet, read on. Otherwise, just don't waste your time and get back to programming.

Just as nested 'if's are satisfied only when all conditions are true, nested 'if not's are satisfied only when all conditions are false. This is similar to what you want to do with an 'or' operand, isn't it?

Even when any one of the conditions in the nested 'if not' is true, the whole statement remains non-satisfied. Hence, you can use negated 'if's in succession by remembering that the body of the condition statement should be what you wanna do if all your nested conditions are false. The body that you actually wanted to give should come under the else statement.

And if you still didn't get the jist of the thing, sorry, I'm 16 and that's the best I can do to explain.

  • x=2 or x=3 => ! ! ( x=2 or x=3) => ! (x != 2 and x !=3) I don't think you can negate the whole if structure to apply the necessary outer "not" operator. It's been 3 years, @Athul-prakash, thoughts? – Azeroth2b Jun 19 '17 at 20:14
1

Only the OR part is tricky, but with a general boolean expression containing NOT OR AND the only nice solution is this:

REM if A == B OR C == C then yes

(call :strequ A B || call :strequ C C) && echo yes
exit /b

:strequ
if "%1" == "%2" exit /b 0
exit /b 1
Henrik4
  • 464
  • 3
  • 13
0

An alternative is to look for a unix shell which does give you logical operators and a whole lot more. You can get a native win32 implementation of a Bourne shell here if you don't want to go the cygwin route. A native bash can be found here. I'm quite certain you could easily google other good alternatives such as zsh or tcsh.

K

Kevin Shea
  • 920
  • 7
  • 12
  • 4
    If you're going to go through the effort of using a different shell, at least go with PowerShell: http://microsoft.com/powershell – Eclipse Mar 15 '10 at 18:18
  • 21
    There are many better shells than DOS. The reason why I would use a DOS bat file is because it doesn't require any external tools. If you have a customer that needs to automate something simple, do you really want them to have to install special tools (cygwin, perl, powershell, etc) when a BAT file will suffice? – Mark Lakata Jul 21 '11 at 00:04
  • 4
    BAT is enough most of the time. 90% of the unix shell scripts ppl write is not pure shell but with many coreutils, sed, awk etc calls. GNU have implemented UNIX goodies in other OS, including Windows. So have a look at this http://getgnuwin32.sourceforge.net/ cmd.exe/bash/zsh plus this should be sufficient on most tasks. No reason to learn so-called PowerShell if you have BAT/UNIX Shell experience – MeaCulpa Apr 17 '12 at 09:30
0

Slight modification to Andry's answer, reducing duplicate type commands:

set "A=1" & set "B=2" & call :IF_AND
set "A=1" & set "B=3" & call :IF_AND
set "A=2" & set "B=2" & call :IF_AND
set "A=2" & set "B=3" & call :IF_AND

echo.

set "A=1" & set "B=2" & call :IF_OR
set "A=1" & set "B=3" & call :IF_OR
set "A=2" & set "B=2" & call :IF_OR
set "A=2" & set "B=3" & call :IF_OR

goto :eof

:IF_OR

(if /i not %A% EQU 1 (
   if /i not %B% EQU 2 (
      echo FALSE-
      type 2>nul
   )
)) && echo TRUE+

goto :eof

:IF_AND


(if /i %A% EQU 1 (
   if /i %B% EQU 2 (
      echo TRUE+
      type 2>nul
   )
)) && echo FALSE-

goto :eof
TedK
  • 11
0

If you need the else clause then you can use this syntax:

AND:

if %v1% == a (if %v2% == b (echo yes) else echo no) else echo no

OR:

if %v1% == a (echo yes) else (if %v2% == b (echo yes) else echo no)
Danny Varod
  • 17,324
  • 5
  • 69
  • 111