ChatGPT解决这个技术问题 Extra ChatGPT

如果...或如果...在 Windows 批处理文件中

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

例如:

IF [%var%] == [1] OR IF [%var%] == [2] ECHO TRUE
不可以。可以直接写 AND:IF [%var%]==[1] IF [%var2%]==[2] ECHO BOTH ARE TRUE。我曾经定义 SET AND=IF,然后写:IF cond1 %AND% cond2 ECHO BOTH ARE TRUE
这回答了你的问题了吗? Logical operators ("and", "or") in DOS batch
使用 SET AND=IF 的好技巧 :-) 但是不要在这种伪逻辑操作之后尝试使用 ELSE :-)

d
dbenham

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

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

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

您可以添加 arasmussen 使用的 ELSE IF 逻辑,因为如果第一个条件为真,它的执行速度可能会快一点,但我从不打扰。

附录 - 这是一个重复的问题,对 Using an OR in an IF statement 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=”之类的选项

通过添加更多代码,即使在 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 - 是的,我已经在答案中注意到了这个限制。但是您的评论迫使我查看答案并意识到 FOR 解决方案还有其他限制。我已经更新了答案的结尾。
findstr 的回声不是一种选择吗?
@Squashman - 嗯,是的,如果您想浏览所有 FINDSTR 错误和怪癖。
答案是错误的。归因于 Aacini 的命令如引用的那样失败,但如果按如下方式编辑则有效:for %%A in ("val1" "val2" "val3" ) do if "%VAR%"==%%A echo true
z
zmbq

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

IF cond1 GOTO foundit
IF cond2 GOTO foundit

ECHO Didn't found it
GOTO end

:foundit
ECHO Found it!

:end

是的,据我所知,这两个是唯一的选择。
=D 我实际上正在学习 powershell 并调整我的所有脚本。但只需要对批处理脚本进行一个小错误修复,并想知道这是否可能。在清洁代码方面我很挑剔哈哈
在许多情况下,CALL 可能比 GOTO 更可取,尽管这仅在您不需要 ELSE 子句时才有效。
@HarryJohnston 它取决于它是否只是一个自上而下的程序/脚本,或者它的结构是否像批处理脚本中存在的函数一样运行=/。在他的示例中,GOTO 是正确的,否则即使找到 ECHO Didn't find it,您也会点击它。
正确的英文应该是“没找到”。我打算编辑这个问题,但确实发现有人已经这样做了,然后发现它被回滚了。
M
Magoo

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

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

简单得多,而且仍然在一条线上。


我发现这是我的批处理脚本中最直接和最简单的用例。为什么这从来没有成为推荐的答案?
谢谢。我不知道,一般来说,upvoting 是一个非常奇怪的过程(而且很可疑?),不仅在 stackoverflow 中,而且在其他论坛中也是如此。但在这种情况下,我想是时候了。这个问题很老,我的回答是最近的。无论如何,当我们能找到任何有效的答案时,我们一定会很高兴。 :)
这种技术的一个可能缺点(尽管我喜欢这种方法的开箱即用!)是根据条件,可能会执行两次命令,这可能是不需要的。
理论上,是的。但是我已经创建了数百个批处理文件,我每天使用几十个,我从来没有遇到过这样的案例。所以让我们继续练习吧! :)
我今天有这样一个案例,我不想执行两次条件。如果文件 a 或文件 b 存在,我想做点什么。
G
Gwenc37

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

不知道它是否可以提供帮助,但我遇到了问题,多亏了你,我发现我认为是另一种基于布尔等价来解决它的方法:

“A or 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

但这仅在两者都不为真时提供 FALSE (ELSE) 分支。如果其中一个为真,则 OP 想要 TRUE 分支。
@dbenham 那将添加 ELSE。答案很棒
@AlexfromJitbit - 是的,如果你可以在两个 IF 语句周围加上括号,然后执行 ELSE,那将给出正确的答案。但是没有简单的方法可以批量执行此操作。这就是为什么经常使用临时辅助变量的原因。
d
dognose

即使这个问题有点老:

如果你想使用 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 而是“就地”操作,如果所有条件都匹配,您可能会执行该操作 3 次。


刚刚发现这个答案已经提供。一定监督过了。
A
Andrew Rasmussen

Batch 中没有 IF <arg> ORELIFELSE IF,但是...

尝试将其他 IF 嵌套在前一个 IF 的 ELSE 中。

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

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

可以使用一个函数来评估 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
) 

+1,此函数非常适合在 ERRORLEVEL 返回码中返回结果。然后调用可以直接使用方便的 && ... || ... 语法而不是额外的 IF ... ELSE ... 语句。
b
bogdan

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

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

() 括号之间的代码块由 CMD 处理为一种(可怜的)子外壳。无论从块中出来的退出代码都将用于确定块在更大的布尔表达式中播放的真/假值。使用这些代码块可以构建任意大的布尔表达式。

简单的例子

每个块被解析为真(即在块中的最后一条语句执行后 ERRORLEVEL = 0)/假,直到整个表达式的值被确定或控制跳出(例如通过 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

佚名
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
)
)

如果我的头,我只是想到了这一点。我可以更压缩它。


A
AKAJim

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

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

k
kayleeFrye_onDeck

虽然 dbenham 的答案非常好,但如果您要检查的变量不是 environment 变量,则依赖 IF DEFINED 会给您带来很多麻烦。脚本变量没有得到这种特殊处理。

虽然这看起来像是一些可笑的无证 BS,但使用 IF /?IF 进行简单的 shell 查询会发现,

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)

u
user8865291

从来没有存在过工作。

如果不存在,我使用 g:xyz/what goto h: Else 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 相同。请注意,每个驱动器都有一个不同的当前文件夹,即使该驱动器不是您当前的工作目录,它也会被“记住”。
B
Ben Personick

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

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

s
sbgib

这很简单,只需在下面使用

IF %var% == 1 (
ECHO TRUE)

IF %var% == 2 (
ECHO TRUE)

a
andronoid

另一种选择是显示当前环境变量并利用 FINDSTR 的默认行为:

FINDSTR "hello there" xy 在文件 xy 中搜索 "hello" 或 "there"

所以

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

在哪里

/I 指定搜索不区分大小写。 /X 打印完全匹配的行。

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

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

编辑:如果变量字符串包含空格,则应使用文字搜索字符串。例如,FINDSTR /I /X /C:"var=1 a" /C:"var=2 b" >NUL


只需将 SET 更改为 SET var,或者最好更改为 (SET var) 2>NUL,您就可以使这个答案更有效。要执行问题中所示的任务,作为单行程序,您只需使用条件执行,即(Set var) 2>NUL | %SystemRoot%\System32\findstr.exe /B /E /I "var=1 var=2" 1>NUL && Echo TRUE
@Compo 使用不带参数的 SET 允许使用不同的变量,例如 my_test_varyour_test_var
您的变量和 OP 的变量被专门命名为 var。在这种情况下列出每个变量是绝对没有必要的。因此效率低下。至少使用 var 只会返回名称以这三个字符开头的那些!
A
August Karlstrom

没有 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 未定义,双引号可防止触发语法错误。


A
Andrew Barber

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

我应该指出的第一件事是,我无法让 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.. Or.. If 语句的方法有关。
很公平。猜猜我是在回答我自己的问题,这些答案对我有帮助,而不是仔细回答 OP 的原始问题。以后会更加小心。谢谢机甲闪! -R
如果您有类似的问题,并且已经自己解决了该问题,并且在 stackoverflow 上没有发布与您相同的问题,您可以将其作为问题提出并选中复选框以自行回答。这样它就会出现在网站上,人们也可以对其做出回应。