Как заставить пакетный файл завершить работу при возникновении ошибки? - PullRequest
256 голосов
/ 09 апреля 2009

У меня есть командный файл, который снова и снова вызывает один и тот же исполняемый файл с разными параметрами. Как сделать так, чтобы он немедленно завершился, если один из вызовов возвращает код ошибки любого уровня?

По сути, я хочу эквивалент MSBuild ContinueOnError=false.

Ответы [ 10 ]

265 голосов
/ 09 апреля 2009

Проверьте errorlevel в операторе if, а затем exit /b (выход только из файла atch b , а не весь процесс 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.

230 голосов
/ 23 января 2012

Добавьте || 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%

См. Также вопрос о выходе из подпрограммы пакетного файла .

76 голосов
/ 20 февраля 2014

Самый короткий:

command || exit /b

Если вам нужно, вы можете установить код выхода:

command || exit /b 666

И вы также можете войти:

command || echo ERROR && exit /b
24 голосов
/ 09 апреля 2009

Одно незначительное обновление, вы должны изменить проверки «if errorlevel 1» на следующее ...

IF %ERRORLEVEL% NEQ 0 

Это потому, что в XP вы можете получить отрицательные числа как ошибки. 0 = нет проблем, все остальное - проблема.

И помните, как DOS обрабатывает тесты "IF ERRORLEVEL". Он вернет true, если номер, который вы проверяете, это число или больше, поэтому, если вы ищете конкретные номера ошибок, вам нужно начать с 255 и продолжить.

10 голосов
/ 18 октября 2017

Вот программа полиглота для 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%

Я использовал этот тип вещей в прошлом для нескольких платформ непрерывная интеграция скрипт.

6 голосов
/ 17 августа 2018

Я предпочитаю ИЛИ форму команды, так как считаю их наиболее читабельными против наличия 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, и если какая-либо из них завершится ошибкой, он выполнит завершиться с тем же кодом завершения, что и с ошибочной командой.

2 голосов
/ 26 ноября 2014

Мы не всегда можем зависеть от ОШИБКИ, потому что внешние программы или пакетные сценарии часто не возвращают коды выхода.

В этом случае мы можем использовать общие проверки для сбоев, как это:

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 голос
/ 05 сентября 2017

Независимо от того, как я пытался, уровень ошибки всегда остается 0, даже если msbuild не удалось. Итак, я построил мой обходной путь:

Сборка проекта и сохранение журнала в Build.log

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

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

поиск строки «0 Error» в журнале сборки, установите результат в 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

0 голосов
/ 25 декабря 2016

Просто используйте ERRORLEVEL для достижения желаемого результата. В команде ERRORLEVEL есть две переменные, которые определяют, если процесс завершился неудачно или успешно, это переменные ERRORLEVEL 0 и ERRORLEVEL 1 (1 для сбоя, 0 для прохождения). Вот пример того, как это будет использоваться в командном файле:

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

Вот ссылка с дополнительной информацией, если она вам нужна: Уровни ошибок

0 голосов
/ 06 сентября 2013
@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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...