Bagaimana cara saya membuat file batch berakhir setelah menemukan kesalahan?

290

Saya memiliki file batch yang memanggil executable yang sama berulang kali dengan parameter yang berbeda. Bagaimana cara saya membuatnya segera berakhir jika salah satu panggilan mengembalikan kode kesalahan dari tingkat apa pun?

Pada dasarnya, saya ingin yang setara dengan MSBuild ContinueOnError=false.

Josh Kodroff
sumber
2
Shell perintah apa yang akan menjalankan skrip Anda? Command.com DOS / Win9x atau cmd.exe Win2k +? Karena itu membuat perbedaan dunia, bisakah Anda menjelaskannya dalam pengeditan pertanyaan Anda?
Mihai Limbășan

Jawaban:

299

Periksa errorleveldalam sebuah ifpernyataan, dan kemudian exit /b(keluar b berkas atch saja, bukan seluruh proses cmd.exe) untuk nilai-nilai selain 0.

same-executable-over-and-over.exe /with different "parameters"
if %errorlevel% neq 0 exit /b %errorlevel%

Jika Anda ingin nilai tingkat kesalahan menyebar di luar file batch Anda

if %errorlevel% neq 0 exit /b %errorlevel%

tetapi jika ini di dalam foritu agak rumit. Anda akan membutuhkan sesuatu yang lebih seperti:

setlocal enabledelayedexpansion
for %%f in (C:\Windows\*) do (
    same-executable-over-and-over.exe /with different "parameters"
    if !errorlevel! neq 0 exit /b !errorlevel!
)

Sunting: Anda harus memeriksa kesalahan setelah setiap perintah. Tidak ada tipe konstruksi "on error goto" global dalam batch cmd.exe / command.com. Saya juga telah memperbarui kode saya per CodeMonkey , meskipun saya belum pernah menemukan tingkat kesalahan negatif dalam salah satu batch-hacking saya di XP atau Vista.

sistem PAUSE
sumber
11
Apakah ada cara untuk menyatakannya sekali untuk seluruh file? "On error goto" atau yang serupa?
Josh Kodroff
3
+1 untuk pemeriksaan tingkat kesalahan negatif. Apakah skrip gagal dalam diam-diam karena hasil negatif.
devstuff
1
Hati-hati: ekspansi yang diaktifkan yang ditunda adalah KRITIS dan juga diperlukan untuk blok if / else atau lainnya
MarcH
1
@ system-PAUSE apakah ada perbedaan antara dua 'jika' pertama ditampilkan?
simpleuser
1
Perluasan tunda diaktifkan / dinonaktifkan atau ekstensi perintah (diperlukan untuk neq) diaktifkan / dinonaktifkan tidak masalah menggunakan if not errorlevel 1 exit /Bseperti yang dijelaskan oleh Microsoft dalam artikel dukungan Menggunakan operator pengalihan perintah dan dalam output bantuan saat menjalankan if /?dalam jendela cmd. Tingkat kesalahan saat ini (kode keluar) terus keluar dari pemrosesan file batch dengan exit /B. Catatan: exitdengan parameter /Bmemerlukan ekstensi perintah yang diaktifkan, lihat Di mana GOTO: EOF kembali ke?
Mofi
252

Tambahkan || goto :labelke setiap baris, lalu tentukan a :label.

Misalnya, buat file .cmd ini:

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

Lihat juga pertanyaan tentang keluar dari subrutin file batch .

Unggas
sumber
4
Ini adalah ungkapan yang sangat umum di sebagian besar bahasa scripting shell, dan berbunyi dengan baik: "Lakukan ini, atau ini jika gagal .."
Fowl
3
Saya menggunakan SET untuk melacak nomor saluran secara manual:command || (SET ErrorLine=102 && goto :error)
SandRock
1
@MarcelValdezOrozco Sepertinya bagi saya ini adalah ||tujuan utama. Mungkin tidak kebagian goto, tetapi "coba, lakukan ini pada kesalahan" seperti Fowl disebutkan. Pertanyaan saya adalah apakah ini berfungsi untuk semua kode keluar yang bukan nol? Hanya positif?
jpmc26
3
@ jpmc26 ya, buktikan sendiri - cmd /k exit -1 && echo success || echo fail- cetakan gagal.
Fowl
2
Anda bahkan dapat menghindari label dengan sesuatu seperticommand || exit /b %errorlevel%
Johannes Brodwall
94

Yang paling pendek:

command || exit /b

Jika perlu, Anda dapat mengatur kode keluar:

command || exit /b 666

Dan Anda juga dapat login:

command || echo ERROR && exit /b
Benoit Blanchon
sumber
4
apakah keluar / b secara kebetulan mengembalikan kode keluar yang gagal asli?
Frank Schwieterman
5
@ FrankSchwieterman, ya, %ERRORLEVEL%tidak tersentuh saat Anda menelepon exit /b, jadi kode kesalahan diteruskan
Benoit Blanchon
24

Satu pembaruan kecil, Anda harus mengubah pemeriksaan "jika tingkat kesalahan 1" menjadi yang berikut ...

IF %ERRORLEVEL% NEQ 0 

Ini karena pada XP Anda bisa mendapatkan angka negatif sebagai kesalahan. 0 = tidak ada masalah, yang lainnya adalah masalah.

Dan perlu diingat cara DOS menangani tes "JIKA ERRORLEVEL". Ini akan mengembalikan true jika nomor yang Anda periksa adalah angka itu atau lebih tinggi jadi jika Anda mencari nomor kesalahan tertentu Anda harus mulai dengan 255 dan menghitung.


sumber
1
Tidak satu pun dari perintah internal dan eksternal standar Windows yang keluar dengan nilai negatif. Microsoft memperingatkan semua penulis program untuk keluar dengan nilai negatif, misalnya pada artikel MSDN tentang Environment.ExitCode Property . Bahkan harus selalu mencari tahu kode keluar mana yang digunakan oleh aplikasi yang berhasil dan mana yang pada berbagai kesalahan, lihat Lokakarya HTML mengembalikan kesalahan setelah berhasil dikompilasi file .chm untuk contoh MS negatif tentang harapan pengguna.
Mofi
17

Berikut adalah program polyglot untuk BASH dan Windows CMD yang menjalankan serangkaian perintah dan berhenti jika ada yang gagal:

#!/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%

Saya telah menggunakan hal semacam ini di masa lalu untuk skrip integrasi berkelanjutan beberapa platform .

Erik Aronesty
sumber
10

Saya lebih suka bentuk perintah ATAU, karena saya menemukan mereka yang paling mudah dibaca (sebagai lawan memiliki jika setelah setiap perintah). Namun, cara naif untuk melakukan hal ini, command || exit /b %ERRORLEVEL%adalah salah .

Ini karena batch memperluas variabel ketika sebuah baris pertama kali dibaca, bukan ketika mereka sedang digunakan. Ini berarti bahwa jika commanddalam baris di atas gagal, file batch keluar dengan benar, tetapi keluar dengan kode pengembalian 0, karena itulah nilai %ERRORLEVEL%pada awal baris. Jelas, ini tidak diinginkan dalam skrip kami, jadi kami harus mengaktifkan ekspansi yang tertunda , seperti:

SETLOCAL EnableDelayedExpansion

command-1 || exit /b !ERRORLEVEL!
command-2 || exit /b !ERRORLEVEL!
command-3 || exit /b !ERRORLEVEL!
command-4 || exit /b !ERRORLEVEL!

Cuplikan ini akan menjalankan perintah 1-4, dan jika salah satu dari mereka gagal, ia akan keluar dengan kode keluar yang sama seperti yang dilakukan oleh perintah yang gagal.

Xarn
sumber
1

Kami tidak selalu dapat bergantung pada ERRORLEVEL, karena berkali-kali program eksternal atau skrip batch tidak mengembalikan kode keluar.

Dalam hal ini kita dapat menggunakan pemeriksaan umum untuk kegagalan seperti ini:

IF EXIST %outfile% (DEL /F %outfile%)
CALL some_script.bat -o %outfile%
IF NOT EXIST %outfile%  (ECHO ERROR & EXIT /b)

Dan jika program mengeluarkan sesuatu ke konsol, kita dapat memeriksanya juga.

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)
Amr Ali
sumber
1

Tidak peduli bagaimana saya mencoba, tingkat kesalahan selalu tetap 0 bahkan ketika msbuild gagal. Jadi saya membangun solusi saya:

Bangun Proyek dan simpan log ke Build.log

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

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

cari string "0 Error" di build log, atur hasilnya ke var

FOR /F "tokens=* USEBACKQ" %%F IN (`find /c /i "0 Error" Build.log`) DO (
    SET var=%%F
)
echo %var%

dapatkan karakter terakhir, yang menunjukkan berapa banyak baris berisi string pencarian

set result=%var:~-1%

echo "%result%"

jika string tidak ditemukan, maka error> 0, build gagal

if "%result%"=="0" ( echo "build failed" )

Solusi itu terinspirasi oleh posting Mechaflash di Cara mengatur output perintah sebagai variabel dalam file batch

dan https://ss64.com/nt/syntax-substring.html

E.Seven
sumber
1
hanya berfungsi untuk jumlah ls dari sepuluh. Lebih baik; for /f %%F in ('type build.log^|find /c /i "0 Error") do set result=%%F. Catatan: find "0 Error"juga akan ditemukan 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
Demican
sumber
4
Harap tambahkan lebih banyak informasi ke jawaban Anda. Hanya satu blok kode tidak terlalu membantu.
PoweredByOrange
Selain tidak menambahkan komentar, cuplikan Anda tidak terlihat sebagai kandidat yang baik untuk menjelaskan fungsionalitas: sepertinya berisi banyak hal yang sama sekali tidak relevan dengan pertanyaan.
Raúl Salinas-Monteagudo