Windows批处理文件中的IF…或IF…


96

有没有办法在Windows批处理文件中写入IF或IF条件语句?

例如:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE

7
否。可以直接写一个AND :IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE。我曾经定义SET AND=IF然后编写:IF cond1 %AND% cond2 ECHO BOTH ARE TRUE
Aacini 2011年

Answers:


95

zmbq解决方案很好,但是不能在所有情况下都使用,例如在FOR FOR(...)循环之类的代码块内。

另一种方法是使用指标变量。将其初始化为未定义,然后仅在任何一个OR条件为true时定义它。然后使用IF DEFINED作为最终测试-无需使用延迟扩展。

FOR ..... DO (
  set "TRUE="
  IF cond1 set TRUE=1
  IF cond2 set TRUE=1
  IF defined TRUE (
    ...
  ) else (
    ...
  )
)

您可以添加arasmussen使用的ELSE IF逻辑,理由是如果第一个条件为true,它可能会更快执行,但我从不打扰。

附录 -这是一个重复的问题,与在IF语句中使用OR的答案几乎完全相同 WinXP Batch Script

最终附录 -我几乎忘记了我最喜欢的技术来测试变量是否为不区分大小写的值列表中的任何一个。初始化包含定界可接受值列表的测试变量,然后使用搜索和替换来测试您的变量是否在列表中。这是非常快的,并且对于任意长的列表使用最少的代码。它确实需要延迟扩展(或CALL %% VAR %%技巧)。而且测试是不区分大小写的。

set "TEST=;val1;val2;val3;val4;val5;"
if "!TEST:;%VAR%;=!" neq "!TEST!" (echo true) else (echo false)

如果VAR包含=,则上述方法可能会失败,因此测试并非万无一失。

如果在需要延迟扩展才能访问VAR当前值的块内进行测试,则

for ... do (
  set "TEST=;val1;val2;val3;val4;val5;"
  for /f %%A in (";!VAR!;") do if "!TEST:%%A=!" neq "!TEST!" (echo true) else (echo false)
)

根据VAR中的期望值,可能需要诸如“ delims =”之类的FOR选项

=通过添加更多代码,即使在VAR中,也可以使上述策略可靠。

set "TEST=;val1;val2;val3;val4;val5;"
if "!TEST:;%VAR%;=!" neq "!TEST!" if "!TEST:;%VAR%;=;%VAR%;"=="!TEST!" echo true

但是现在,除非添加指示符变量,否则我们将失去提供ELSE子句的能力。该代码看起来有点“丑陋”,但是我认为这是测试VAR是否为任意大小写不敏感选项中任何一种的最佳性能可靠方法。

最后,有一个更简单的版本,我认为它稍慢一些,因为它必须为每个值执行一个IF。Aacini在前面提到的链接中对已接受答案的评论中提供了此解决方案

for %%A in ("val1" "val2" "val3" "val4" "val5") do if "%VAR%"==%%A echo true

值列表不能包含*或?字符和值,并且%VAR%不应包含引号。如果%VAR%还包含空格或特殊字符(如等)^,则引号会导致问题&。此解决方案的另一个限制是,除非您添加指示符变量,否则它不提供ELSE子句的选项。优点是,根据是否存在IF /I选项,它可以区分大小写或不区分大小写。


遗憾的是,由于文件匹配的语义,for不适用于包含问号的值,例如FOR %% A IN(-?-h -help)。
Killroy

@Killroy-是的,我已经在回答中指出了这一限制。但是您的评论迫使我仔细考虑答案,并意识到FOR解决方案还有其他限制。我已经更新了答案的结尾。
dbenham

回显findstr是不是一种选择?
Squashman

@Squashman-gh,是的,如果您想浏览所有FINDSTR错误和怪癖。
dbenham

答案是错误的。归属于Aacini的命令无法成功引用,但按以下方式进行编辑时可以使用:对于%% A in(“ val1”“ val2”“ val3”),如果“%VAR%” == %% A,则执行true
Ed999

54

我不这么认为。只需使用两个IF和GOTO相同的标签:

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end

是的,据我所知,这是唯一的选择。
Mechaflash 2011年

1
= D我实际上正在学习Powershell和调整我所有的脚本。但是只需要对批处理脚本进行小的错误修复,并想知道是否可行。对于干净的代码,我很挑剔
Mechaflash 2011年

1
在许多情况下,CALL可能比GOTO更可取,尽管只有在不需要ELSE子句的情况下,CALL才有效。
哈里·约翰斯顿

@HarryJohnston取决于它只是一个自上而下的程序/脚本,还是其结构能够像批处理脚本= /中存在的函数那样运行。在他的示例中,GOTO是正确的,否则ECHO Didn't find it即使找到它,您也将击中它。
Mechaflash 2011年

让蝙蝠支持or运算符有多困难?它尚未在2019

8

感谢这篇文章,它对我有很大帮助。

Dunno如果可以解决问题,但我遇到了问题,感谢您,我发现我认为这是基于布尔等价物的另一种解决方法:

“ A或B”与“不是(不是A且不是B)”相同

从而:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE

成为:

IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE

但这仅在都不成立的情况下提供FALSE(ELSE)分支。如果OP为真,则OP希望为TRUE分支。
dbenham 2014年

8

可以在一行中使用简单的“ FOR”以使用“或”条件:

FOR %%a in (item1 item2 ...) DO IF {condition_involving_%%a} {execute_command}  

适用于您的情况:

FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE

我发现这是批处理脚本中最直接,最简单的用例。为什么从来没有把它作为推荐答案呢?
myusrn '18

谢谢。我不知道,总的来说投票是一个非常奇怪的过程(而且是可疑的?),不仅在stackoverflow中,而且在其他论坛中。但是在这种情况下,我想是时候了。这个问题很老,我的回答最近。无论如何,当我们找到可行的答案时,我们必须感到高兴。:)
Apostolos

这种技术的一个可能缺点(尽管我喜欢这种方法的开箱即用!),取决于条件可能有可能两次执行该命令,而这是不必要的。
TripeHound

从理论上讲,是的。但是我创建了数百个批处理文件,每天使用数十个批处理文件,但从未遇到过这种情况。因此,让我们继续练习吧!:)
Apostolos

6

即使这个问题稍大一些:

如果要使用if cond1 or cond 2-不应使用复杂的循环或类似的东西。

简单地提供彼此ifs之后的结合goto-这是一个隐式或。

//thats an implicit IF cond1 OR cond2 OR cond3
if cond1 GOTO doit
if cond2 GOTO doit
if cond3 GOTO doit

//thats our else.
GOTO end

:doit
  echo "doing it"

:end

如果没有所有条件,则没有goto而是执行“ inplace”操作,则可以执行3次该操作。


刚刚发现,此答案已提供。主人监督了这一点。
dognose 2014年

2

没有IF <arg> ORELIFELSE IF批处理,但是...

尝试将其他IF嵌套在上一个IF的ELSE内。

IF <arg> (
    ....
) ELSE (
    IF <arg> (
        ......
    ) ELSE (
        IF <arg> (
            ....
        ) ELSE (
    )
)

3
这不是OR的良好实现,因为必须为每个ELSE IF复制要执行的条件代码。(当然,条件代码不是GOTO,在这种情况下,您将具有zmbq解决方案的更详细形式。)
dbenham 2011年

2

可以使用一个函数,该函数对“或”逻辑求值并返回单个值。

@echo off
set var1=3
set var2=5
call :logic_or orResult "'%var1%'=='4'" "'%var2%'=='5'"
if %orResult%==1 ( 
    echo At least one expression is true
) ELSE echo All expressions are false
exit /b

:logic_or <resultVar> expression1 [[expr2] ... expr-n] 
SETLOCAL
set "logic_or.result=0"
set "logic_or.resultVar=%~1"

:logic_or_loop 
if "%~2"=="" goto :logic_or_end 
if %~2 set "logic_or.result=1"
SHIFT 
goto :logic_or_loop 

:logic_or_end 
( 
  ENDLOCAL 
  set "%logic_or.resultVar%=%logic_or.result%"
  exit /b
) 

+1,此函数是在ERRORLEVEL返回码中返回结果的理想选择。然后,该调用可以&& ... || ...直接使用便捷的语法而不是额外的IF ... ELSE ...语句。
dbenham 2014年

2

可以通过间接使用IF来实现此目标。

下面是一个复杂表达式的示例,可以在CMD批处理中非常简洁和逻辑地编写,而无需使用不连贯的标签和GOTO。

()括号之间的代码块由CMD处理为(可悲的)子外壳。块中出现的退出代码将用于确定该块在较大的布尔表达式中播放的真/假值。可以使用这些代码块构建任意大的布尔表达式。

简单的例子

每个块都解析为true(即,执行完该块中的最后一条语句后ERRORLEVEL = 0)/ false,直到确定了整个表达式的值或控制跳出(例如,通过GOTO):

 ((DIR c:\xsgdde /w) || (DIR c:\ /w)) && (ECHO -=BINGO=-)

复杂的例子

这解决了最初提出的问题。每个块中可能有多个语句,但||中可能 || || 表达式,最好是简洁明了,以便尽可能可读。^是CMD批处理中的转义字符,当放在一行的末尾时,它将转义EOL并指示CMD在下一行继续读取当前的语句批处理。

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION

(
    (CALL :ProcedureType1 a b) ^
        || (CALL :ProcedureType2 sgd) ^
            || (CALL :ProcedureType1 c c)
) ^
    && (
        ECHO -=BINGO=-
        GOTO :EOF
    )
ECHO -=no bingo for you=-
GOTO :EOF

:ProcedureType1
    IF "%~1" == "%~2" (EXIT /B 0) ELSE (EXIT /B 1)
GOTO :EOF (this line is decorative as it's never reached)

:ProcedureType2
    ECHO :ax:xa:xx:aa:|FINDSTR /I /L /C:":%~1:">nul
GOTO :EOF

1
If %x%==1 (
If %y%==1 (
:: both are equal to 1.
)
)

那是为了检查多个变量是否相等。这是其中一个变量。

If %x%==1 (
:: true
)
If %x%==0 (
If %y%==1 (
:: true
)
)
If %x%==0 (
If %y%==0 (
:: False
)
)

我只是想过顶一下。我可以进一步压缩它。


1

我知道这个问题很旧,但是我想发布一个替代解决方案,以防其他人(例如我自己)在遇到相同问题时发现该线程。通过回显变量并使用findstr进行验证,我能够解决缺少OR运算符的问题。

for /f %%v in ('echo %var% ^| findstr /x /c:"1" /c:"2"') do (
    if %errorlevel% equ 0 echo true
)

1

尽管dbenham的答案相当不错,但是IF DEFINED如果要检查的变量不是环境,依靠它可能会给您带来麻烦变量。脚本变量没有得到特殊处理。

尽管这看起来像是一些可笑的未记录的BS,但通过对IFwith 进行简单的shell查询可以IF /?发现,

DEFINED条件条件的工作方式类似于EXIST,不同之处在于它采用 环境变量名称,并且如果定义了环境变量,则返回true 。

关于回答这个问题,是否有理由在一系列评估之后不仅仅使用一个简单的标志?OR在底层逻辑和可读性方面,这对我来说似乎是最灵活的检查。例如:

Set Evaluated_True=false

IF %condition_1%==true (Set Evaluated_True=true)
IF %some_string%=="desired result" (Set Evaluated_True=true)
IF %set_numerical_variable% EQ %desired_numerical_value% (Set Evaluated_True=true)

IF %Evaluated_True%==true (echo This is where you do your passing logic) ELSE (echo This is where you do your failing logic)

显然,它们可以是任何类型的条件评估,但我仅分享一些示例。

如果您想将所有内容写在一行上,那么可以&&像下面这样将它们链接在一起:

Set Evaluated_True=false

IF %condition_1%==true (Set Evaluated_True=true) && IF %some_string%=="desired result" (Set Evaluated_True=true) && IF %set_numerical_variable% EQ %desired_numerical_value% (Set Evaluated_True=true)

IF %Evaluated_True%==true (echo This is where you do your passing logic) ELSE (echo This is where you do your failing logic)

0

从来没有存在上班。

如果不存在,我使用g:xyz /转到h:其他xcopy c:current / files g:bu / current有修饰符/ a等。不确定哪个。笔记本电脑在店里。和办公室里的电脑。我不在那里。

从来没有批处理文件可以在Windows XP上运行


如您的示例中所写,“如果不存在g:xyz / what”,则xyz / what相对于g:驱动器的当前目录,该目录可能不是g的根文件夹。您在这里需要“ g:\ xyz \ what”吗?与c:current / files和g:bu / current相同。请注意,每个驱动器都有一个不同的当前文件夹,即使该驱动器不是您的当前工​​作目录,它也会被“记住”。
John Elion

0

我通常使用的一种更快的替代方法如下,因为我可以“或”任意数量的条件以适应可变空间

@(
  Echo off
  Set "_Match= 1 2 3 "
)

Set /a "var=3"

Echo:%_Match%|Find " %var% ">nul || (
  REM Code for a false condition goes here
) && (
  REM code for a true condition goes here.
)

-3

意识到这是一个古老的问题,这些答复帮助我提出了一个解决方案,用于测试批处理文件的命令行参数。所以我也想发布我的解决方案,以防其他人正在寻找类似的解决方案。

我应该指出的第一件事是,我无法使IF ... ELSE语句在FOR ... DO子句中工作。事实证明(感谢dbenham在示例中无意中指出了这一点),ELSE语句不能与结尾处分开。

所以代替这个:

FOR ... DO (
    IF ... (
    )
    ELSE (
    )
)

出于可读性和美学原因,这是我的偏爱,您必须这样做:

FOR ... DO (
    IF ... (
    ) ELSE (
    )
)

现在,ELSE语句不会作为无法识别的命令返回。

最后,这就是我要尝试的操作-我希望能够以任意顺序将多个参数传递给批处理文件,忽略大小写,并对传入的未定义参数进行报告/失败。因此,这就是我的解决方案...

@ECHO OFF
SET ARG1=FALSE
SET ARG2=FALSE
SET ARG3=FALSE
SET ARG4=FALSE
SET ARGS=(arg1 Arg1 ARG1 arg2 Arg2 ARG2 arg3 Arg3 ARG3)
SET ARG=

FOR %%A IN (%*) DO (
    SET TRUE=
    FOR %%B in %ARGS% DO (
        IF [%%A] == [%%B] SET TRUE=1
        )
    IF DEFINED TRUE (
        SET %%A=TRUE
        ) ELSE (
        SET ARG=%%A
        GOTO UNDEFINED
        )
    )

ECHO %ARG1%
ECHO %ARG2%
ECHO %ARG3%
ECHO %ARG4%
GOTO END

:UNDEFINED
ECHO "%ARG%" is not an acceptable argument.
GOTO END

:END

请注意,这只会报告第一个失败的参数。因此,如果用户传入了多个不可接受的参数,则只会在第一个被纠正之前告诉他们第一个,然后第二个以此类推。


-1这个问题与“ FOR循环中的IF语法”无关,也与如何正确传递参数无关,但与在批处理文件中发现一种复制If ..或..If语句的方式无关。
Mechaflash 2012年

1
很公平。猜猜我在回答自己的问题,这些回答对我有帮助,而不是谨慎地回答OP的原始问题。以后会更加小心。谢谢Mechaflash!-R
RMWChaos 2012年

1
如果您本质上有类似的问题,已经自己解决了该问题,并且在stackoverflow上没有发布与您自己的问题相同的问题,则可以将其提出一个问题并选中相应的框以自行回答。这样,它将出现在网站上,人们也可以对此做出响应。
Mechaflash 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.