ฉันจะทำให้ไฟล์แบตช์สิ้นสุดลงเมื่อพบข้อผิดพลาดได้อย่างไร


290

ฉันมีไฟล์แบทช์ที่เรียกใช้ไฟล์ปฏิบัติการเดียวกันซ้ำแล้วซ้ำอีกโดยมีพารามิเตอร์ต่างกัน ฉันจะทำให้มันยุติลงทันทีได้อย่างไรหากการโทรหนึ่งครั้งส่งคืนรหัสข้อผิดพลาดในระดับใด?

โดยทั่วไปฉันต้องการเทียบเท่า ContinueOnError=falseMSBuild


2
เชลล์คำสั่งใดที่จะรันสคริปต์ของคุณ command.com ของ DOS / Win9x หรือ cmd.exe ของ Win2k + เนื่องจากสิ่งนั้นทำให้โลกแตกต่างคุณช่วยอธิบายได้ไหมว่าในการแก้ไขคำถามของคุณ?
Mihai Limbășan

คำตอบ:


299

ตรวจสอบerrorlevelใน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
มีวิธีการระบุไว้หนึ่งครั้งสำหรับไฟล์ทั้งหมดหรือไม่? "ข้อผิดพลาดข้ามไป" หรืออะไรที่คล้ายกัน?
Josh Kodroff

3
+1 สำหรับการตรวจสอบข้อผิดพลาดระดับลบ มีสคริปต์ล้มเหลวอย่างเงียบ ๆ เนื่องจากผลลบ
devstuff

1
ระวัง: การขยายตัวล่าช้าที่เปิดใช้งานเป็นสิ่งสำคัญและจำเป็นสำหรับ if / else หรือบล็อกอื่น ๆ
MarcH

1
@ ระบบ - หยุดชั่วคราวมีความแตกต่างระหว่างสอง 'ถ้า' แสดง?
simpleuser

1
การขยายตัวล่าช้าเปิดใช้งาน / ส่วนขยายที่ปิดหรือคำสั่ง (ที่จำเป็นสำหรับการneq) เปิด / ปิดไม่ได้เรื่องเกี่ยวกับการใช้if not errorlevel 1 exit /Bตามที่อธิบายไว้โดย Microsoft ในบทความการสนับสนุนการใช้ประกอบการเปลี่ยนเส้นทางคำสั่งและในการส่งออกช่วยเหลือในการทำงานif /?ในหน้าต่าง cmd ปัจจุบัน errorlevel (รหัสออก) 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
มันเป็นสำนวนที่พบบ่อยมากในภาษาสคริปต์เชลล์ส่วนใหญ่และมันอ่านได้ดี: "ทำสิ่งนี้หรือสิ่งนี้ถ้ามันล้มเหลว .. "
Fowl

3
ฉันใช้ SET เพื่อติดตามหมายเลขบรรทัดด้วยตนเอง:command || (SET ErrorLine=102 && goto :error)
SandRock

1
@MarcelValdezOrozco ดูเหมือนกับฉันว่านี่คือสิ่งที่||ถูกสร้างขึ้นในครั้งแรก อาจจะไม่ได้ข้ามโดยเฉพาะ แต่ "ลองทำสิ่งนี้โดยผิดพลาด" ตามที่ Fowl พูดถึง คำถามของฉันใช้ได้กับรหัสออกที่ไม่ใช่ศูนย์ทั้งหมดหรือไม่ บวกเท่านั้น?
jpmc26

3
@ jpmc26 ใช่แล้วพิสูจน์ด้วยตัวคุณเอง - cmd /k exit -1 && echo success || echo fail- พิมพ์ล้มเหลว
ไก่

2
คุณสามารถหลีกเลี่ยงฉลากที่มีบางอย่างเช่นcommand || exit /b %errorlevel%
Johannes Brodwall

95

ที่สั้นที่สุด:

command || exit /b

หากคุณต้องการคุณสามารถตั้งรหัสออก:

command || exit /b 666

และคุณยังสามารถเข้าสู่ระบบ:

command || echo ERROR && exit /b

4
ออก / b โดยบังเอิญส่งคืนรหัสการออกเดิมที่ล้มเหลวหรือไม่
Frank Schwieterman

5
@ FrankSchwieterman ใช่%ERRORLEVEL%ไม่ถูกแตะต้องเมื่อคุณโทรexit /bดังนั้นรหัสข้อผิดพลาดจะถูกส่งต่อ
เบอนัวต์บ

24

อัปเดตเล็กน้อยหนึ่งรายการคุณควรเปลี่ยนการตรวจสอบ "ถ้า errorlevel 1" เป็นรายการต่อไปนี้ ...

IF %ERRORLEVEL% NEQ 0 

นี่เป็นเพราะใน XP คุณจะได้รับตัวเลขติดลบว่าเป็นข้อผิดพลาด 0 = ไม่มีปัญหาอะไรเป็นปัญหา

และจำไว้ว่าวิธีที่ DOS จัดการกับการทดสอบ "IF ERRORLEVEL" มันจะกลับมาจริงถ้าหมายเลขที่คุณกำลังตรวจสอบคือหมายเลขนั้นหรือสูงกว่าดังนั้นหากคุณกำลังมองหาหมายเลขข้อผิดพลาดเฉพาะคุณต้องเริ่มต้นด้วย 255 และทำงาน


1
ไม่มีคำสั่งภายในและภายนอกมาตรฐานของ Windows ที่ออกจากตัวเคยด้วยค่าลบ ไมโครซอฟท์เตือนนักเขียนโปรแกรมใด ๆ เพื่อออกมีมูลค่าเชิงลบเช่นในบทความ MSDN เกี่ยวกับEnvironment.ExitCode ทรัพย์สิน ในความเป็นจริงมันจะต้องค้นหาเสมอว่ารหัสทางออกใดที่แอปพลิเคชันใช้ในการประสบความสำเร็จและข้อใดในข้อผิดพลาดต่าง ๆ ให้ดูที่HTML Help Workshop ส่งคืนข้อผิดพลาดหลังจากรวบรวมไฟล์. 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ในบรรทัดด้านบนล้มเหลวชุดแบตช์จะออกอย่างถูกต้อง แต่มันออกมาพร้อมกับรหัสส่งคืน 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

ไม่ว่าฉันจะพยายามอย่างไรระดับข้อผิดพลาดจะยังคงอยู่ที่ 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


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

นอกจากจะไม่มีการเพิ่มความคิดเห็นใด ๆ ตัวอย่างของคุณก็ดูเหมือนจะไม่ดีสำหรับการอธิบายฟังก์ชั่นการใช้งาน: ดูเหมือนจะมีหลายสิ่งหลายอย่างที่ไม่เกี่ยวข้องกับคำถาม
Raúl Salinas-Monteagudo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.