遇到错误如何使批处理文件终止?


290

我有一个批处理文件,使用不同的参数反复调用同一可执行文件。如果其中一个调用返回任何级别的错误代码,如何使其立即终止?

基本上,我想要等效于MSBuild的ContinueOnError=false


2
哪个命令外壳程序将运行您的脚本?DOS / Win9x的command.com或Win2k +的cmd.exe?既然这与众不同,那么您可以在对问题的编辑中澄清一下吗?
Mihai Limbășan 09年

Answers:


299

检查errorlevelin if语句,然后exit /b(仅退出b atch文件,而不退出整个cmd.exe进程)以获取非0的值。

same-executable-over-and-over.exe /with different "parameters"
if %errorlevel% neq 0 exit /b %errorlevel%

如果您希望错误级别的值传播到批处理文件之外

if %errorlevel% neq 0 exit /b %errorlevel%

但是如果在里面,for那会有些棘手。您将需要更多类似的东西:

setlocal enabledelayedexpansion
for %%f in (C:\Windows\*) do (
    same-executable-over-and-over.exe /with different "parameters"
    if !errorlevel! neq 0 exit /b !errorlevel!
)

编辑:您必须在每个命令后检查错误。cmd.exe / command.com批处理中没有全局的“出错时出错”类型的构造。我还更新了每个CodeMonkey的代码,尽管在XP或Vista上的任何批量黑客攻击中都从未遇到过负面的错误级别。


11
有没有办法为整个文件声明一次?“出现错误时转到”或类似内容?
乔什·科德洛夫

3
+1用于否定错误级别检查。如果脚本由于负面结果而默默失败。
devstuff'sep

1
注意:enabledelayedexpansion是至关重要的,并且对于if / else或任何其他块也是必需的
MarcH 2013年

1
@ system-PAUSE显示的前两个“ if”之间有什么区别吗?
simpleuser 2016年

1
启用/禁用延迟扩展或启用/禁用命令扩展(如要求neqif not errorlevel 1 exit /B与Microsoft 无关,如Microsoft在支持文章“ 使用命令重定向运算符”和在if /?cmd窗口中运行的帮助输出中所述。当前的错误级别(退出代码)在使用退出批处理文件时保持不变exit /B。注意:exit使用参数/B需要启用命令扩展名,请参阅GOTO:EOF返回何处?
Mofi

252

添加|| goto :label到每一行,然后定义一个:label

例如,创建此.cmd文件:

@echo off

echo Starting very complicated batch file...
ping -invalid-arg || goto :error
echo OH noes, this shouldn't have succeeded.
goto :EOF

:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

另请参见有关退出批处理文件子例程的问题


4
在大多数shell脚本语言中,这是一个非常常见的习惯用法,它读起来很好:“执行此操作,否则将失败。”
Fowl,2012年

3
我使用SET手动跟踪行号:command || (SET ErrorLine=102 && goto :error)
SandRock

1
@MarcelValdezOrozco在我看来,这就是||最初创建的目的。也许不是特别地转到goto,而是像Fowl所说的“尝试,在出错时执行此操作”。我的问题是这对所有非零退出代码都有效吗?只积极?
2013年

3
@ jpmc26是的,向您自己证明cmd /k exit -1 && echo success || echo fail-打印失败。
Fowl

2
您甚至可以避免使用类似这样的标签command || exit /b %errorlevel%
Johannes Brodwall,2016年

94

最短的:

command || exit /b

如果需要,可以设置退出代码:

command || exit /b 666

您还可以登录:

command || echo ERROR && exit /b

4
退出/ b偶然返回失败的原始退出代码吗?
Frank Schwieterman

5
@FrankSchwieterman,是的,%ERRORLEVEL%在您致电时没有受到影响exit /b,因此将转发错误代码
Benoit Blanchon 2015年

24

一个较小的更新,您应该将“ if errorlevel 1”的检查更改为以下内容:

IF %ERRORLEVEL% NEQ 0 

这是因为在XP上您会得到负数作为错误。0 =没问题,其他都是问题。

并记住DOS处理“ IF ERRORLEVEL”测试的方式。如果您要检查的数字是该数字或更高,它将返回true,因此,如果您要查找特定的错误号,则需要从255开始并向下计算。


1
Windows标准的内部和外部命令都不会以负值退出。Microsoft警告任何程序编写者都必须使用负值退出,例如MSDN上有关Environment.ExitCode Property的文章。实际上,必须始终找出应用程序成功使用了哪些退出代码,以及各种错误所导致的退出代码,请参见HTML Help Workshop在成功编译.chm文件后返回错误,以获取用户期望的否定MS示例。
Mofi

17

这里有一个 用于BASH和Windows CMD多语言程序程序运行一系列命令,如果其中任何一个失败,则退出:

#!/bin/bash 2> nul

:; set -o errexit
:; function goto() { return $?; }

command 1 || goto :error

command 2 || goto :error

command 3 || goto :error

:; exit 0
exit /b 0

:error
exit /b %errorlevel%

过去,我已经将这种类型的东西用于多平台持续集成脚本。


10

我更喜欢OR形式的命令,因为我发现它们最易读(相对于每个命令后面都有一个if)。但是,这样做的天真方法command || exit /b %ERRORLEVEL%错误的

这是因为批处理在第一次读取行时而不是在使用行时扩展变量。这意味着,如果command以上行中的失败,则批处理文件会正确退出,但它会以返回码0退出,因为那是%ERRORLEVEL%该行开头的值。显然,这在我们的脚本中是不可取的,因此我们必须启用 延迟扩展,如下所示:

SETLOCAL EnableDelayedExpansion

command-1 || exit /b !ERRORLEVEL!
command-2 || exit /b !ERRORLEVEL!
command-3 || exit /b !ERRORLEVEL!
command-4 || exit /b !ERRORLEVEL!

此代码段将执行命令1-4,并且如果其中任何一个失败,它将以与失败命令相同的退出代码退出。


1

我们不能总是依赖ERRORLEVEL,因为很多时候外部程序或批处理脚本不会返回退出代码。

在这种情况下,我们可以对此类失败使用常规检查:

IF EXIST %outfile% (DEL /F %outfile%)
CALL some_script.bat -o %outfile%
IF NOT EXIST %outfile%  (ECHO ERROR & EXIT /b)

而且,如果程序输出了一些要控制台的内容,我们也可以对其进行检查。

some_program.exe 2>&1 | FIND "error message here" && (ECHO ERROR & EXIT /b)
some_program.exe 2>&1 | FIND "Done processing." || (ECHO ERROR & EXIT /b)

1

无论我如何尝试,即使msbuild失败,错误级别也始终保持为0。所以我建立了解决方法:

生成项目并将日志保存到Build.log

SET Build_Opt=/flp:summary;logfile=Build.log;append=true

msbuild "myproj.csproj" /t:rebuild /p:Configuration=release /fl %Build_Opt%

在构建日志中搜索“ 0错误”字符串,将结果设置为var

FOR /F "tokens=* USEBACKQ" %%F IN (`find /c /i "0 Error" Build.log`) DO (
    SET var=%%F
)
echo %var%

获取最后一个字符,该字符指示包含搜索字符串的行数

set result=%var:~-1%

echo "%result%"

如果找不到字符串,则错误> 0,构建失败

if "%result%"=="0" ( echo "build failed" )

该解决方案的灵感来自Mechaflash在如何将命令输出设置为批处理文件中的变量的文章

https://ss64.com/nt/syntax-substring.html


1
仅适用于计数lss少于十。更好; for /f %%F in ('type build.log^|find /c /i "0 Error") do set result=%%F。注意:find "0 Error"也会找到10 Errors
斯蒂芬,

-2
@echo off

set startbuild=%TIME%

C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe c:\link.xml /flp1:logfile=c:\link\errors.log;errorsonly /flp2:logfile=c:\link\warnings.log;warningsonly || goto :error

copy c:\app_offline.htm "\\lawpccnweb01\d$\websites\OperationsLinkWeb\app_offline.htm"

del \\lawpccnweb01\d$\websites\OperationsLinkWeb\bin\ /Q

echo Start Copy: %TIME%

set copystart=%TIME%

xcopy C:\link\_PublishedWebsites\OperationsLink \\lawpccnweb01\d$\websites\OperationsLinkWeb\ /s /y /d

del \\lawpccnweb01\d$\websites\OperationsLinkWeb\app_offline.htm

echo Started Build: %startbuild%
echo Started Copy: %copystart%
echo Finished Copy: %TIME%

c:\link\warnings.log

:error

c:\link\errors.log

4
请在您的答案中添加更多信息。仅仅一段代码不是很有帮助。
PoweredByOrange 2013年

除了未添加任何注释外,您的代码段看起来也不是解释功能的理想之选:它似乎包含许多与问题完全无关的内容。
劳尔·萨利纳斯-蒙塔古多
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.