开发者

Logical operators ("and", "or") in DOS batch

开发者 https://www.devze.com 2022-12-18 00:14 出处:网络
How would you implement logical operators in DOS Bat开发者_Python百科ch files?You can do and with nested conditions:

How would you implement logical operators in DOS Bat开发者_Python百科ch files?


You can do and with nested conditions:

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

or:

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.


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 /?


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


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


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!


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.


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


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! ;)


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.


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


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
)


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


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)


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
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号