오류 발생시 배치 파일을 종료하려면 어떻게해야합니까?


290

다른 매개 변수를 사용하여 동일한 실행 파일을 반복해서 호출하는 배치 파일이 있습니다. 호출 중 하나가 어떤 수준의 오류 코드를 반환하면 즉시 종료합니까?

기본적으로 MSBuild와 동등한 것을 원합니다 ContinueOnError=false.


2
어떤 명령 셸이 스크립트를 실행합니까? DOS / Win9x의 command.com 또는 Win2k +의 cmd.exe? 그것이 세상을 변화시키기 때문에, 당신은 당신의 질문을 편집하여 그것을 명확히 할 수 있습니까?
Mihai Limbășan 2009

답변:


299

을 확인 errorlevelif다음 문, 및 exit /b(출구 B의 0이 아닌 값 ATCH 파일 만이 아닌 전체 cmd.exe를 프로세스).

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 배치에는 전역 "on error goto"유형의 구문이 없습니다. XP 또는 Vista의 배치 해킹에서 부정적인 오류 수준이 발생하지는 않았지만 CodeMonkey 별로 코드를 업데이트했습니다 .


11
전체 파일에 대해 한 번만 진술하는 방법이 있습니까? "오류 발생시"또는 이와 유사한 것?
Josh Kodroff 2009

3
음의 오류 수준 검사의 경우 +1 부정적인 결과로 인해 스크립트가 자동으로 실패했습니다.
devstuff

1
주의 : enabledelayedexpansion은 중요하며 if / else 또는 다른 블록에도 필요합니다
MarcH

1
@ system-PAUSE 처음 두 'if'사이에 차이점이 있습니까?
simpleuser

1
지원 확장 명령 neq비활성화 연산자 사용 및 cmd 창 에서 실행시 도움말 출력에 if not errorlevel 1 exit /B설명 된대로 지연 확장 활성화 / 비활성화 또는 명령 확장 (필수 ) 활성화 / 비활성화는 중요하지 않습니다 . 현재 오류 수준 (종료 코드)은로 배치 파일 처리를 종료 할 때 유지됩니다 . 참고 : 매개 변수를 사용 하려면 명령 확장이 활성화 되어 있어야합니다 . GOTO : EOF는 어디로 돌아 옵니까?를 참조하십시오 . if /?exit /Bexit/B
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
대부분의 쉘 스크립팅 언어에서 매우 일반적인 관용구이며, "이것이 아니면 실패하면 이것을한다."
Fowl

3
SET를 사용하여 줄 번호를 수동으로 추적합니다.command || (SET ErrorLine=102 && goto :error)
SandRock

1
@MarcelValdezOrozco는 이것이 ||처음에 만들어진 것 같습니다 . 어쩌면 Fowl이 언급했듯이 특히 시도하지는 않지만 "실제로 시도하십시오". 내 질문은 이것이 0이 아닌 모든 종료 코드에서 작동합니까? 긍정 만?
jpmc26

3
@ jpmc26 네, 그렇습니다 cmd /k exit -1 && echo success || echo fail. 스스로 증명하십시오 -인쇄가 실패합니다.
Fowl

2
당신은 같은과 라벨을 피할 수command || exit /b %errorlevel%
요하네스 Brodwall

95

가장 짧은 :

command || exit /b

필요한 경우 종료 코드를 설정할 수 있습니다.

command || exit /b 666

그리고 당신은 또한 기록 할 수 있습니다 :

command || echo ERROR && exit /b

4
/ b가 우연히 원래의 실패한 종료 코드를 반환합니까?
Frank Schwieterman

5
@FrankSchwieterman, 예, %ERRORLEVEL%전화를 걸면 손대지 exit /b않으므로 오류 코드가 전달됩니다.
Benoit Blanchon

24

하나의 사소한 업데이트, "오류 수준 1 인 경우"에 대한 검사를 다음과 같이 변경해야합니다.

IF %ERRORLEVEL% NEQ 0 

XP에서는 음수를 오류로 얻을 수 있기 때문입니다. 0 = 문제 없음, 다른 문제가 있습니다.

그리고 DOS가 "IF ERRORLEVEL"테스트를 처리하는 방식을 명심하십시오. 확인중인 숫자가 그 숫자 이상이면 true를 반환하므로 특정 오류 번호를 찾고 있다면 255로 시작하여 작동해야합니다.


1
Windows 표준 내부 및 외부 명령은 음수 값으로 종료되지 않습니다. Microsoft는 모든 프로그램 작성기에 음수 값으로 종료하도록 경고합니다 (예 : Environment.ExitCode Property 에 대한 MSDN 기사) . 실제로 성공시 응용 프로그램에서 사용되는 종료 코드와 다양한 오류 중 어떤 종료 코드를 사용해야하는지 항상 알아야합니다 . 사용자 기대치에 대한 부정적인 MS 예제 는 HTML 도움말 제작에서 .chm 파일성공적으로 컴파일 한 후 오류를 반환 합니다.를 참조하십시오 .
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, 위의 행에서 실패하면 배치 파일이 올바르게 종료되지만 값 %ERRORLEVEL%이 행의 시작 부분에 있었기 때문에 리턴 코드 0으로 종료됩니다 . 분명히 이것은 스크립트에서 바람직하지 않으므로 다음과 같이 지연 확장 을 활성화해야합니다 .

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 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


1
lss보다 10보다 작은 경우에만 작동합니다. 보다 나은; for /f %%F in ('type build.log^|find /c /i "0 Error") do set result=%%F. 참고 : find "0 Error"또한 찾을 수 10 Errors있습니다.
Stephan

-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

주석을 추가하지 않은 것 외에도 스 니펫은 기능을 설명하는 데 적합하지 않습니다. 질문과는 전혀 관련이없는 내용이 많이 포함되어있는 것 같습니다.
Raúl Salinas-Monteagudo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.