我可以在DOS批处理文件中使用IF块吗?


96

在DOS批处理文件中,如果语句主体只有1行?我想我发现我可以在某处使用()if块,就像在{}类似C的编程语言中所使用的那样,但是当我尝试这样做时,它并没有执行语句。也没有错误消息。这是我的代码:

if %GPMANAGER_FOUND%==true(echo GP Manager is up
goto Continue7
)
echo GP Manager is down
:Continue7

奇怪的是,运行批处理文件时,“ GP Manager已启动”或“ GP Manager已关闭”都没有打印出来。



是的,有帮助。DOS很烂。如果我要在是否使用多个语句,否则必须在语句之间使用&&?还是有一种更优雅的方式?
休·达令

Answers:


139

您确实可以放置一个语句块,在条件语句后执行。但是语法错误。括号必须严格按照如下所示使用:

if <statement> (
    do something
) else (
    do something else
)

但是,我不认为else-if语句有任何内置语法。不幸的是,您将需要创建嵌套的if语句块来进行处理。


其次,该%GPMANAGER_FOUND% == true测试对我来说似乎非常可疑。我不知道将环境变量设置为什么或如何设置它,但是我非常怀疑所显示的代码是否会产生所需的结果。


以下示例代码对我来说很好用:

@echo off

if ERRORLEVEL == 0 (
    echo GP Manager is up
    goto Continue7
)
echo GP Manager is down
:Continue7

请注意有关我的示例代码的一些具体细节:

  • 在条件语句的末尾与左括号之间添加的空格。
  • 我将设置@echo off为避免在执行时看到打印到控制台的所有语句,而是仅查看专门以开头的语句的输出echo
  • 我使用内置ERRORLEVEL变量作为测试。在这里阅读更多

1
如果%ERRORLEVEL%== 0,则更好地使用,因为另一个变量始终为true,因为如果ERRORLEVEL <N>为true,则如果errorlevel等于或大于<N>,则在这种情况下将忽略“ ==”
jeb

@jeb:我想您可能错过了重点。使用ERRORLEVEL并不能解决他的问题。我只是发布了正确语法的示例。在这种情况下,可以接受任何一种形式,就像if 0 == 0其他任何琐碎的表达一样。但是确实,请确保您了解环境变量%ERRORLEVEL%ERRORLEVEL命令处理器内部之间的区别。Raymond Chen 在此博客中对此进行了很好的解释。
科迪·格雷

您可以拥有ELSE IF吗?
xagyg

1
除了@mythofechelon的注释之外,即使REM语句中看似无害的右括号也将结束该块。例如,REM This is a comment (or so I thought)扔进IF街区会让你搞砸。
rkagerer 2015年

2
@mythofechelon和@rkagerer都指出了一般规则中需要引用字符串的特定问题。您永远不要编写代码, IF %somevar%==example_string2 因为它应该始终是代码,因此操作数应解析为 IF "value_of_somevar"=="example_string2“以避免在任一字符串操作数中出现特殊字符,从而导致语句中的语法错误IF。应始终执行设置的值,因为 set "somevar=value_of_somevar" 该语法允许您将变量值中的特殊字符转义,请注意我的意思不是 set somevar="value_of_somevar"
跳过R

15

从逻辑上讲,科迪的答案应该起作用。但是我不认为命令提示符在逻辑上处理代码块。为了我的一生,除了块中的单个命令,我无法使其正常工作。就我而言,广泛的测试表明,该块内的所有命令均已缓存,并在该块末尾同时执行。当然,这不会产生预期的结果。这是一个过于简化的示例:

if %ERRORLEVEL%==0 (
set var1=blue
set var2=cheese
set var3=%var1%_%var2%
)

应该为var3提供以下值:

blue_cheese

但是却产生了:

_

因为在退出代码块时,所有3个命令均被缓存并同时执行。

通过重写if块以仅执行一个命令goto并添加一些标签,我能够解决此问题。它笨拙,我不太喜欢它,但至少它能起作用。

if %ERRORLEVEL%==0 goto :error0
goto :endif

:error0
set var1=blue
set var2=cheese
set var3=%var1%_%var2%

:endif

8
使用延迟扩展应该可以工作:使用:set var3=!var1!_!var2!
Dracorat

4

代替使用goto混乱,尝试使用&符号或双&符号(以错误级别0为条件)作为命令分隔符。

总而言之,我修复了一个脚本片段,以总结一下,我有三个批处理文件,一个在找到外部备份驱动器已分配的字母后调用另外两个。我将第一个文件保留在主外部驱动器上,因此对其备份例程的调用工作正常,但是对第二个文件的调用需要更改活动的驱动器。下面的代码显示了我如何修复它:

for %%b in (d e f g h i j k l m n o p q r s t u v w x y z) DO (
if exist "%%b:\Backup.cmd" %%b: & CALL "%%b:\Backup.cmd"
)

为什么这在地球上被否决了?这正是我所需要的。
ggb667

1
@ GCB667-为了澄清@Louis,他写了一个“答案”,该答案与为什么IF语句不适用于原始海报的问题无关。它与“ vinniejohnson”的答案(也错过了原始海报问题)有关。
跳过[R

1

我在批处理文件中通过与IF命令相关的搜索返回的结果浏览了这篇文章,并且我忍不住纠正这一错误观念的机会,即IF块仅限于单个命令。以下是生产Windows NT命令脚本的一部分,该脚本每天在我撰写此回复的计算机上运行。

    if "%COPYTOOL%" equ "R" (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using RoboCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    %TOOLPATH% %SRCEPATH% %DESTPATH% /copyall %RCLOGSTR% /m /np /r:0 /tee
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Robocopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
) else (
    WWLOGGER.exe "%APPDATA%\WizardWrx\%~n0.LOG" "Using XCopy to make a backup of %USERPROFILE%\My Documents\Outlook Files\*"
    call %TOOLPATH%  "%USERPROFILE%\My Documents\Outlook Files\*" "%USERPROFILE%\My Documents\Outlook Files\_backups" /f /m /v /y
    C:\BIN\ExitCodeMapper.exe C:\BIN\ExitCodeMapper.INI[Xcopy] %TEMP%\%~n0.TMP %ERRORLEVEL%
)

也许两行或更多行的代码块仅适用于Windows NT命令脚本(.CMD文件),因为对仅限于老式批处理(.BAT)文件的应用程序的生产脚本目录的搜索仅显示了一个命令代码块。由于该应用程序已经过扩展维护(这意味着我没有积极参与支持它),所以我不能说那是因为我不需要多条线,还是不能使它们正常工作。

无论哪种情况,如果后者是正确的话,都有一个简单的解决方法;将多行移动到单独的批处理文件或批处理文件子例程中。我知道后者可以在两种脚本中使用。


0

也许有点晚了,但希望它能成功:

@echo off 

if %ERRORLEVEL% == 0 (
msg * 1st line WORKS FINE rem You can relpace msg * with any othe operation...
goto Continue1
)
:Continue1
If exist "C:\Python31" (
msg * 2nd line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue2
)
:Continue2
If exist "C:\Python31\Lib\site-packages\PyQt4" (  
msg * 3th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue3
)
:Continue3
msg * 4th line WORKS FINE rem You can relpace msg * with any othe operation...
    goto Continue4
)
:Continue4
msg * "Tutto a posto" rem You can relpace msg * with any othe operation...
pause
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.