How do I make a batch file terminate upon encountering an error?
我有一个批处理文件,使用不同的参数反复调用同一可执行文件。 如果其中一个调用返回任何级别的错误代码,如何使其立即终止?
基本上,我想要等效于MSBuild的
检查
1 2 | same-executable-over-and-over.exe /with different"parameters" if %errorlevel% neq 0 exit /b %errorlevel% |
如果您希望错误级别的值传播到批处理文件之外
1 | if %errorlevel% neq 0 exit /b %errorlevel% |
但是,如果它在
1 2 3 4 5 | 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上的任何批量黑客攻击中都从未遇到过负面的错误级别。
将
例如,创建此.cmd文件:
1 2 3 4 5 6 7 8 9 10 | @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% |
另请参阅有关退出批处理文件子例程的问题。
最短的:
1 | command || exit /b |
如果需要,可以设置退出代码:
1 | command || exit /b 666 |
您还可以登录:
1 | command || echo ERROR && exit /b |
一个较小的更新,您应该将" if errorlevel 1"的检查更改为以下内容:
1 | IF %ERRORLEVEL% NEQ 0 |
这是因为在XP上您会得到负数作为错误。 0 =没问题,其他都是问题。
并记住DOS处理" IF ERRORLEVEL"测试的方式。如果您要检查的数字是该数字或更高,它将返回true,因此,如果您要查找特定的错误号,则需要从255开始并向下计算。
这是用于BASH和Windows CMD的多语言程序,该程序运行一系列命令并在其中任何一个失败时退出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/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% |
过去,我已经将这种类型的东西用于多平台持续集成脚本。
我更喜欢OR形式的命令,因为我发现它们最易读(如
而不是在每个命令之后都加上if)。但是,幼稚的方式
这样做
这是因为第一次读取一行时批处理会扩展变量,而不是
比使用它们时要多。这意味着如果
上面的操作失败,批处理文件会正确退出,但是会以返回码0退出,
因为那是
线。显然,这在我们的脚本中是不可取的,因此我们必须启用
延迟扩展,如下所示:
1 2 3 4 5 6 | SETLOCAL EnableDelayedExpansion command-1 || exit /b !ERRORLEVEL! command-2 || exit /b !ERRORLEVEL! command-3 || exit /b !ERRORLEVEL! command-4 || exit /b !ERRORLEVEL! |
该代码段将执行命令1-4,如果其中任何一个失败,它将
使用与失败命令相同的退出代码退出。
无论我如何尝试,即使msbuild失败,错误级别也始终保持为0。所以我建立了解决方法:
生成项目并将日志保存到Build.log
1 2 3 | SET Build_Opt=/flp:summary;logfile=Build.log;append=true msbuild"myproj.csproj" /t:rebuild /p:Configuration=release /fl %Build_Opt% |
在构建日志中搜索" 0错误"字符串,将结果设置为var
1 2 3 4 | FOR /F"tokens=* USEBACKQ" %%F IN (`find /c /i"0 Error" Build.log`) DO ( SET var=%%F ) echo %var% |
获取最后一个字符,该字符指示包含搜索字符串的行数
1 2 3 | set result=%var:~-1% echo"%result%" |
如果找不到字符串,则错误> 0,构建失败
1 | if"%result%"=="0" ( echo"build failed" ) |
该解决方案的灵感来自Mechaflash在如何将命令输出设置为批处理文件中的变量的文章中
和https://ss64.com/nt/syntax-substring.html
我们不能总是依赖ERRORLEVEL,因为很多时候外部程序或批处理脚本不会返回退出代码。
在这种情况下,我们可以对此类失败使用常规检查:
1 2 3 | IF EXIST %outfile% (DEL /F %outfile%) CALL some_script.bat -o %outfile% IF NOT EXIST %outfile% (ECHO ERROR & EXIT /b) |
而且,如果程序输出了一些要控制台的内容,我们也可以对其进行检查。
1 2 | 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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | echo off cls ping localhost errorlevel 0 goto :good errorlevel 1 goto :bad :good cls echo Good! echo[ pause exit :bad cls echo Bad! echo[ pause exit |
如果需要,这里是带有更多信息的链接:错误级别
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | @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 |