在 Windows 批处理文件中执行 IF... 或 IF...

有没有办法在 windows 批处理文件中写一个 IF 或 IF If判断语句?

例如:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
397091 次浏览

我不这么认为。只要使用两个 IF 和 GOTO 同一个标签:

IF cond1 GOTO foundit
IF cond2 GOTO foundit


ECHO Didn't found it
GOTO end


:foundit
ECHO Found it!


:end

There is no IF <arg> OR or ELIF or ELSE IF in Batch, however...

尝试在前一个 IF 的 ELSE 中嵌套另一个 IF。

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

Zmbq 解决方案很好,但不能在所有情况下使用,比如在 FORDO (...)循环这样的代码块内。

另一种方法是使用指示器变量。将其初始化为未定义,然后仅当 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 逻辑,理由是如果第一个条件为真,那么它的执行速度可能会稍微快一点,但是我从不费事。

附录 -这是一个重复的问题,几乎相同的答案 < a href = “ https://stackoverflow./q/7273433/1012053”> 在 IF 语句中使用 OR WinXP 批处理脚本

最后附录 -我几乎忘记了我最喜欢的测试变量是否是不区分大小写的值列表中的任何一个的技术。初始化包含可接受值的分隔列表的测试变量,然后使用搜索和替换来测试变量是否在列表中。这非常快,并且对任意长的列表使用最少的代码。它确实需要延迟扩展(或者使用 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选项。

意识到这是一个有点老的问题,回答帮助我想出了一个解决方案来测试命令行参数到一个批处理文件; 所以我想张贴我的解决方案,以防其他人也在寻找类似的解决方案。

First thing that I should point out is that I was having trouble getting IF ... ELSE statements to work inside of a FOR ... DO clause. Turns out (thanks to dbenham for inadvertently pointing this out in his examples) the ELSE statement cannot be on a separate line from the closing parens.

所以不是这样:

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

注意,这只会报告第一个失败的参数。因此,如果用户传入多个不可接受的参数,他们只会被告知第一个参数,直到它被纠正,然后第二个参数,等等。

可以使用一个函数来计算 OR 逻辑并返回一个值。

@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
)

即使这个问题再老一点:

如果你想使用 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

如果所有条件都匹配,那么除了一个“ inplace”操作之外没有 goto,您可以执行该操作3次。

感谢这篇文章,它帮了我很多。

不知道这是否有帮助,但我有这个问题,感谢你,我发现了我认为是另一种解决它的方法,基于这个布尔等价:

“ A 或 B”与“ not (not A and not B)”相同

因此:

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

成为:

IF not [%var%] == [1] IF not [%var%] == [2] ECHO FALSE
If %x%==1 (
If %y%==1 (
:: both are equal to 1.
)
)

That's for checking if multiple variables equal value. Here's for either variable.

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

我刚刚想到,如果我的头顶。我可以压缩它更多。

我意识到这个问题已经过时了,但是我想发布一个替代的解决方案,以防其他人(比如我自己)在发现这个帖子的时候有同样的问题。我能够通过回显变量并使用 findstr 进行验证来解决缺少 OR 操作符的问题。

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

这个目标可以通过间接地使用 IF 来实现。

下面是一个复杂表达式的例子,它可以在 CMD 批处理中非常简洁和逻辑地编写,没有不一致的标签和 GOTO。

()括号之间的代码块由 CMD 作为一种(可悲的)子 shell 处理。无论从一个块中出来什么样的退出代码,都将用于确定该块在更大的布尔表达式中的 true/false 值。可以用这些代码块构建任意大的布尔表达式。

Simple example

Each block is resolved to true (i.e. ERRORLEVEL = 0 after the last statement in the block has executed) / false, until the value of the whole expression has been determined or control jumps out (e.g. via 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

虽然 dbenham 的答案相当不错,但是如果要检查的变量不是 环境变量,那么依赖 IF DEFINED可能会给您带来很多麻烦。脚本变量不会得到这种特殊对待。

虽然这可能看起来像一些可笑的没有文档的废话,但是使用 IF /?IF进行简单的 shell 查询就会发现,

DEFINED 条件的工作方式与 EXIST 类似,只是它接受 Environment 变量名,如果 环境 变量 定义。

关于回答这个问题,是否有理由在一系列评估之后不仅仅使用一个简单的标志?对我来说,这似乎是最灵活的 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)

从没存在过。

我吸毒 如果不存在 g: xyz/what goto h: 否则,xcopy c: current/files g: bu/current 有修饰语/a 等等。不确定是哪些。商店里的笔记本电脑。办公室里的电脑。我不在那里。

从来没有批处理文件在 WindowsXP 之上工作

一个简单的“ FOR”可以用在一行中来表示一个“ or”条件:

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

适用于你的情况:

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

禁止执行两次

一条评论指出,{execute_command}可能会遇到两次。为了避免这种情况,您可以在第一次遭遇后使用 goto。

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

如果您认为 {execute_command}有可能执行两次 你不会想这样的,那么您可以添加 && goto :eof:

FOR %%a in (1 2) DO IF %var%==%%a ECHO TRUE && goto :eof

简单多了,而且还在一条线上。

我通常使用的一个快得多的替代方案如下所示,因为我可以“或”任意数量的条件,可以适应变量空间

@(
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.
)

它很简单,只要使用下面

IF %var% == 1 (
ECHO TRUE)


IF %var% == 2 (
ECHO TRUE)

Another option is to display the current environment variables and exploit the default behaviour of FINDSTR:

FINDSTR "hello there" x.y在文件 x.y 中搜索“ hello”或者“ there”。

那么

SET | FINDSTR /I /X "var=1 var=2" >NUL
IF %ERRORLEVEL% EQU 0 (
ECHO TRUE
) ELSE (
ECHO FALSE
)

在哪里

/I    Specifies that the search is not to be case-sensitive.
/X    Prints lines that match exactly.

如果首选正则表达式,则使用 FINDSTR /R /I "^var=1$ ^var=2$" >NUL

编辑: 如果变量字符串包含空格,则应使用 FINDSTR /R,例如,FINDSTR /R /I "^var=1 a$ ^var=2 b$" >NUL

编辑: 如果变量字符串包含空格,则应使用文字搜索字符串。

没有 OR 运算符,但是您可以编写(伪代码)

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

喜欢

IF "%var%" == "1" SET "match=y"
IF "%var%" == "2" SET "match=y"
IF DEFINED match ECHO TRUE

注意,如果 Var未定义,双引号可防止触发语法错误。

我通过构建一个外部函数 IF 的可调用且干净的抽象将 Bogdan 的解决方案提升到了一个新的层次,这样就可以在内联块中使用它。如果您无论如何都要构建一个批处理库,那么就不要再进一步查看了。

lib.cmd

@ECHO OFF
SETLOCAL ENABLEEXTENSIONS
SHIFT & GOTO:%1
: Common batch extension library.


:::
: Performs conditional processing in batch programs. Is callable for inline use.
: Arguments:
:   %1 - /I for case-insensitive comparison on strings, can be skipped for case-sensitive comparison.
:   %2 - NOT to negate the result, can be skipped.
:   %3 - EXIST for file checks or first string to compare with, also supports "string1"=="string2" (full condition).
:   %4 - If EXIST is specified, path to the directory or file.
:        Otherwise if %3 is not a full condition, this argument has to be one of:
:        - ==   Compares both strings to be equal using lstrcmpW or lstrcmpiW (case-insensitive).
:        - EQU  Converts both strings to numbers and checks if they are equal.
:        - NEQ  Converts both strings to numbers and checks if they are not equal.
:        - LSS  Converts both strings to numbers and checks if the first is lesser than the second.
:        - LEQ  Converts both strings to numbers and checks if the first is lesser or equal than the second.
:        - GTR  Converts both strings to numbers and checks if the first is greater than the second.
:        - GEQ  Converts both strings to numbers and checks if the first is greater or equal than the second.
:        If a string cannot be parsed to a number, its numeric representation will be used.
:        This argument can be skipped, so == will be used.
:   %5 - If %3 is not a full condition, this argument has to be the second string to compare.
: Outputs:
:   Nothing
: Returns:
:   0, if the condition is met, 1 otherwise
:::
:test-if
IF "%~1"=="/I" SET "I=/I " & SHIFT
IF "%~1"=="/i" SET "I=/I " & SHIFT
IF "%~1"=="NOT" SET "NOT=NOT " & SHIFT
IF "%~1"=="not" SET "NOT=NOT " & SHIFT
IF "%~1"=="EXIST" SET "EXIST=EXIST " & SHIFT
IF "%~1"=="exist" SET "EXIST=EXIST " & SHIFT


SET "string1=%~1%"
IF "%~3"=="" (
SET "comp=^=^="
SET "string2=%~2"
) ELSE (
SET "comp=%~2"
SET "string2=%~3"
)
IF %I%%NOT%%EXIST% "%string1%" %comp% "%string2%" (
ENDLOCAL & EXIT /B 0
)
ENDLOCAL & EXIT /B 1

用法

( ( CALL lib test-if "%1" == "foo" ) || ( CALL lib test-if "%1" == "bar" ) ) && (
ECHO "Argument is foo or bar"
)
  • lib是 lib.cmd 的路径,对于 cmd 文件,后缀 .cmd不是必需的
  • 任何 IF 语法都与此抽象兼容,所以您也可以执行类似 test-if EXIST "path"test-if not 300 LSS 200的操作
  • test-if "%1" == "foo"中的 ==将被批量剥离,我在自己的案例中解决了这个问题,但是这导致 test-if "%1" "foo"也是有效的,尽管它不是标准。