Bir hatayla karşılaştığında toplu iş dosyasının sonlandırılmasını nasıl sağlayabilirim?


290

Farklı parametreleri ile tekrar tekrar aynı yürütülebilir çağıran bir toplu iş dosyası var. Çağrılardan biri herhangi bir düzeydeki hata kodunu döndürürse derhal sonlandırılmasını nasıl sağlayabilirim?

Temel olarak, MSBuild'in eşdeğerini istiyorum ContinueOnError=false.


2
Komut dosyanızı hangi komut kabuğu çalıştıracak? DOS / Win9x'in command.com veya Win2k + 's cmd.exe? Bu fark yaratan bir dünya yarattığından, sorunuzun bir düzenlemesinde bunu netleştirebilir misiniz?
Mihai Limbăşan

Yanıtlar:


299

Giriş errorlevelbir in ifardından açıklamada ve exit /b(çıkmak b 0'dan başka değerler için atch dosyasını değil, yalnızca tüm cmd.exe süreci).

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

Hata seviyesinin değerinin toplu iş dosyanızın dışına yayılmasını istiyorsanız

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

ama eğer bu bir içindeyse forbiraz zorlaşır. Daha fazla şeye ihtiyacınız olacak:

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

Düzenle: Her komuttan sonra hatayı kontrol etmeniz gerekir. Cmd.exe / command.com toplu işinde global bir "hataya gitme" türü yoktur. XP veya Vista'da toplu iş korsanlığımın hiçbirinde olumsuz bir hata düzeyiyle karşılaşmamamıza rağmen, CodeMonkey'e göre kodumu da güncelledim .


11
Tüm dosya için bir kez belirtmenin bir yolu var mı? "Hata gitti" ya da benzer bir şey?
Josh Kodroff

3
Negatif hata seviyesi kontrolü için +1. Bir senaryo olumsuz bir sonuç yüzünden sessizce başarısız oldu.
Devstuff


1
@ system-PAUSE Gösterilen ilk iki 'if' arasında herhangi bir fark var mı?
simpleuser

1
Gecikmeli genişletme etkin / devre dışı veya etkin / devre dışı bırakılmış komut uzantıları (gerekli neq) if not errorlevel 1 exit /B, destek makalesinde Microsoft tarafından açıklandığı gibi kullanılması önemli değildir Komut yeniden yönlendirme işleçlerini kullanma ve if /?cmd penceresinde çalıştırma konusunda yardım çıktısı Geçerli hata düzeyi (çıkış kodu) ile toplu iş dosyasının işlenmesinden çıkılıyor exit /B. Not: exitparametre /Betkin komut uzantıları gerektirdiğinde, bkz. GOTO: EOF nereye geri dönüyor?
Mofi

252

|| goto :labelHer satıra ekleyin ve ardından a :label.

Örneğin, bu .cmd dosyasını oluşturun:

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

Toplu iş dosyası alt yordamından çıkma ile ilgili soruya da bakın .


4
Çoğu kabuk betik dilinde çok yaygın bir deyimdir ve iyi okur: "Bunu yapın, eğer başarısız olursa bunu yapın .."
Fowl

3
Satır numarasını manuel olarak takip etmek için bir SET kullanıyorum:command || (SET ErrorLine=102 && goto :error)
SandRock

1
@MarcelValdezOrozco Bana öyle geliyor ki ||, ilk etapta bunun için yaratıldı. Belki özellikle gitmemekle birlikte, Fowl'ın belirttiği gibi "bunu deneyin, hatayla yapın". Benim sorum bu sıfır olmayan tüm çıkış kodları için çalışıyor mu? Sadece pozitif mi?
jpmc26

3
@ jpmc26 evet öyle, kendinize kanıtlayın cmd /k exit -1 && echo success || echo fail- baskılar başarısız.
Fowl

2
Etiketleri bile önleyebilirsinizcommand || exit /b %errorlevel%
Johannes Brodwall

95

En kısa:

command || exit /b

Gerekirse, çıkış kodunu ayarlayabilirsiniz:

command || exit /b 666

Ayrıca şunları da kaydedebilirsiniz:

command || echo ERROR && exit /b

4
çıkış / b tesadüfen başarısız olan çıkış kodunu döndürür mü?
Frank Schwieterman

5
@FrankSchwieterman, evet, %ERRORLEVEL%aradığınızda dokunulmaz exit /b, bu nedenle hata kodu iletilir
Benoit Blanchon

24

Küçük bir güncelleme, "eğer hata seviyesi 1" için kontrolleri aşağıdaki şekilde değiştirmeniz gerekir ...

IF %ERRORLEVEL% NEQ 0 

Bunun nedeni XP'de negatif sayıları hata olarak alabilmenizdir. 0 = sorun yok, başka bir şey sorun.

Ve DOS "ERRORLEVEL IF" testlerini işleme biçimini unutmayın. Kontrol ettiğiniz sayı bu sayı veya daha yüksekse true değerini döndürecektir, bu nedenle belirli hata numaraları arıyorsanız 255 ile başlayıp aşağı doğru çalışmanız gerekir.


1
Windows standart iç ve dış komutlarının hiçbiri negatif değerle çıkmaz. Microsoft, herhangi bir program yazarı, örneğin Environment.ExitCode Özelliği hakkındaki MSDN makalesinde, negatif bir değerle çıkması için uyarır . Aslında, bir uygulama tarafından hangi çıkış kodunun başarılı olarak kullanıldığını ve çeşitli hatalarda hangilerinin kullanıldığını her zaman bulmak gerekir , kullanıcı beklentileri hakkında olumsuz bir MS örneği için .chm dosyasını başarıyla derledikten sonra HTML Yardım Atölyesi hata döndürür .
Mofi

17

İşte BASH ve Windows CMD için bir dizi komut çalıştıran ve bunlardan herhangi biri başarısız olursa çıkmayı sağlayan bir çok dilli program :

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

Geçmişte bu tür bir şeyi çoklu platform sürekli entegrasyon komut dosyası için kullandım.


10

Onları en okunabilir bulduğum için OR komutunu tercih ederim (her komuttan sonra bir if olması yerine). Ancak bunu yapmanın naif yolu command || exit /b %ERRORLEVEL%olduğunu yanlış .

Bunun nedeni, bir satır, bir satır ilk okunduğunda değil, kullanıldığında değil değişkenleri genişletmesidir. Bu, commandyukarıdaki satırda başarısız olursa, toplu iş dosyasının düzgün bir şekilde çıktığı, ancak 0 dönüş koduyla çıktığı anlamına gelir , çünkü değerin %ERRORLEVEL%satırın başında olduğu şey budur . Açıkçası, bu senaryomuzda istenmeyen bir durumdur, bu nedenle gecikmeli genişlemeyi etkinleştirmeliyiz , şöyle:

SETLOCAL EnableDelayedExpansion

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

Bu snippet, 1-4 komutlarını yürütür ve bunlardan herhangi biri başarısız olursa, başarısız komutuyla aynı çıkış koduyla çıkar.


1

Her zaman ERRORLEVEL'e güvenemeyiz, çünkü çoğu kez harici programlar veya toplu komut dosyaları çıkış kodlarını döndürmez.

Bu durumda, aşağıdaki gibi arızalar için genel kontrolleri kullanabiliriz:

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

Ve program konsol için bir şey çıkarırsa, bunu da kontrol edebiliriz.

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

Nasıl denediğim önemli değil, msbuild başarısız olsa bile hata seviyesi her zaman 0 olarak kalır. Bu yüzden geçici çözümümü oluşturdum:

Proje oluşturma ve günlüğü Build.log dosyasına kaydetme

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

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

build log'da "0 Error" dizesini arayın, sonucu var olarak ayarlayın

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

arama dizesini kaç satır içerdiğini gösteren son karakteri al

set result=%var:~-1%

echo "%result%"

dize bulunamazsa, hata> 0, derleme başarısız oldu

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

Bu çözüm, Mechaflash'ın bir toplu iş dosyasında komut çıktısını değişken olarak ayarlama konusundaki gönderisinden ilham aldı

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


1
yalnızca ondan büyük sayılar için çalışır. Daha iyi; for /f %%F in ('type build.log^|find /c /i "0 Error") do set result=%%F. Not: find "0 Error"ayrıca bulacak 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
Lütfen cevabınıza daha fazla bilgi ekleyin. Sadece bir kod bloğu çok yararlı değil.
PoweredByOrange

Yorum eklememenin yanı sıra, snippet'iniz bir işlevi açıklamak için iyi bir aday gibi görünmüyor: soru ile tamamen alakasız birçok şey içeriyor gibi görünüyor.
Raúl Salinas-Monteagudo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.