ฉันมีไฟล์แบทช์ที่เรียกใช้ไฟล์ปฏิบัติการเดียวกันซ้ำแล้วซ้ำอีกโดยมีพารามิเตอร์ต่างกัน ฉันจะทำให้มันยุติลงทันทีได้อย่างไรหากการโทรหนึ่งครั้งส่งคืนรหัสข้อผิดพลาดในระดับใด?
โดยทั่วไปฉันต้องการเทียบเท่า ContinueOnError=false
MSBuild
ฉันมีไฟล์แบทช์ที่เรียกใช้ไฟล์ปฏิบัติการเดียวกันซ้ำแล้วซ้ำอีกโดยมีพารามิเตอร์ต่างกัน ฉันจะทำให้มันยุติลงทันทีได้อย่างไรหากการโทรหนึ่งครั้งส่งคืนรหัสข้อผิดพลาดในระดับใด?
โดยทั่วไปฉันต้องการเทียบเท่า ContinueOnError=false
MSBuild
คำตอบ:
ตรวจสอบ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 ก็ตาม
neq
) เปิด / ปิดไม่ได้เรื่องเกี่ยวกับการใช้if not errorlevel 1 exit /B
ตามที่อธิบายไว้โดย Microsoft ในบทความการสนับสนุนการใช้ประกอบการเปลี่ยนเส้นทางคำสั่งและในการส่งออกช่วยเหลือในการทำงานif /?
ในหน้าต่าง cmd ปัจจุบัน errorlevel (รหัสออก) exit /B
จะถูกเก็บไว้บนออกจากการประมวลผลของไฟล์ชุดด้วย หมายเหตุ: exit
ด้วยพารามิเตอร์/B
ต้องใช้ส่วนขยายคำสั่งที่เปิดใช้งานดูGOTO: EOF กลับไปที่ใด
เพิ่มไปยังแต่ละบรรทัดและจากนั้นกำหนด|| 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%
command || (SET ErrorLine=102 && goto :error)
||
ถูกสร้างขึ้นในครั้งแรก อาจจะไม่ได้ข้ามโดยเฉพาะ แต่ "ลองทำสิ่งนี้โดยผิดพลาด" ตามที่ Fowl พูดถึง คำถามของฉันใช้ได้กับรหัสออกที่ไม่ใช่ศูนย์ทั้งหมดหรือไม่ บวกเท่านั้น?
cmd /k exit -1 && echo success || echo fail
- พิมพ์ล้มเหลว
command || exit /b %errorlevel%
ที่สั้นที่สุด:
command || exit /b
หากคุณต้องการคุณสามารถตั้งรหัสออก:
command || exit /b 666
และคุณยังสามารถเข้าสู่ระบบ:
command || echo ERROR && exit /b
%ERRORLEVEL%
ไม่ถูกแตะต้องเมื่อคุณโทรexit /b
ดังนั้นรหัสข้อผิดพลาดจะถูกส่งต่อ
อัปเดตเล็กน้อยหนึ่งรายการคุณควรเปลี่ยนการตรวจสอบ "ถ้า errorlevel 1" เป็นรายการต่อไปนี้ ...
IF %ERRORLEVEL% NEQ 0
นี่เป็นเพราะใน XP คุณจะได้รับตัวเลขติดลบว่าเป็นข้อผิดพลาด 0 = ไม่มีปัญหาอะไรเป็นปัญหา
และจำไว้ว่าวิธีที่ DOS จัดการกับการทดสอบ "IF ERRORLEVEL" มันจะกลับมาจริงถ้าหมายเลขที่คุณกำลังตรวจสอบคือหมายเลขนั้นหรือสูงกว่าดังนั้นหากคุณกำลังมองหาหมายเลขข้อผิดพลาดเฉพาะคุณต้องเริ่มต้นด้วย 255 และทำงาน
นี่คือโปรแกรมหลายภาษาสำหรับ 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%
ฉันเคยใช้สิ่งนี้ในอดีตสำหรับสคริปต์การรวมต่อเนื่องหลายแพลตฟอร์ม
ฉันชอบรูปแบบ 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 และหากมีข้อผิดพลาดใด ๆ มันจะออกด้วยรหัสการออกเช่นเดียวกับคำสั่งที่ล้มเหลว
เราไม่สามารถพึ่งพา 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)
ไม่ว่าฉันจะพยายามอย่างไรระดับข้อผิดพลาดจะยังคงอยู่ที่ 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 ที่วิธีตั้งค่าคำสั่งเอาต์พุตเป็นตัวแปรในไฟล์แบตช์
for /f %%F in ('type build.log^|find /c /i "0 Error") do set result=%%F
. หมายเหตุ: นอกจากนี้ยังจะได้พบกับfind "0 Error"
10 Errors
@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