2010-07-12 9 views
14

Ich habe ein Problem mit meiner Batch-Datei. Es mehrere Programme automatisch baut so etwas wie dies tun:Batch-Skript aus einer Funktion heraus beenden

  • einige Kompilation Flags gesetzt
  • run ‚gmake alle‘
  • Aufruf der „überprüfen Fehlerstufe“ Funktion und wenn Errorlevel 1, Ausfahrt

So sieht es wie folgt aus:

set FLAG=1 
... 
gmake all 
call :interactive_check 
set OTHERFLAG=1 
... 
gmake all 
call :interactive_check 

es 6 oder 7 von diesen (und i t könnte wachsen). Also habe ich eine Funktion gemacht, die errorlevel prüft, anstatt sie bei jedem Schritt zu kopieren/einzufügen. Das Problem ist folgendes: die Fehlerüberprüfung wird durch eine Funktion gemacht:

:interactive_check 
if errorlevel 1 (
echo. 
echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
echo Error in compilation process... exiting 
echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
echo. 
cd %root_dir% 
exit /B 1 
) ELSE (
echo.Continuing to next step 
) 
goto:eof 

Nun, wenn es ausgeführt wird, die exit /B 1 verlässt einfach die Funktion, aber nicht die Batch-Datei.

Wissen Sie, wie Sie die komplette Batch-Datei beenden, ohne bei jedem Schritt mein "if errorlevel 1 .." kopieren/einfügen zu müssen?

+2

Sie können nicht. Ersetzen Sie einfach 'call: interactive_check' durch' if errorlevel 1 goto error'. Es gibt keinen großen Unterschied zwischen Copy-Pasting-Former oder Letzterem. :) – atzz

+0

Habe es, löste das Problem damit und es funktioniert gut, danke! – Gui13

Antwort

16

einen fatalen Syntaxfehler verwenden, wie jeb zeigt, tut alle Batch-Verarbeitung töten, aber es hat auch eine unangenehme Nebenwirkung - Umwelt ändert sich nach SETLOCAL erhalten bleiben, auch wenn sie über implizite ENDLOCAL verworfen werden sollen wenn die Stapelverarbeitung endet. Weitere Informationen finden Sie in meinen DosTips-Posts SETLOCAL continues after batch termination!.

Basierend auf Informationen unter Why does a non-interactive batch script think I've pressed control-C?, habe ich eine saubere Möglichkeit gefunden, alle Batch-Scripting aus einer CALLed Routine oder einem Skript zu beenden, und alle Änderungen nach SETLOCAL werden ordnungsgemäß verworfen.

Hier ist Beispiel Ausgabe der oben genannten test.bat. Sie können sehen, dass das Skript nie aus dem Aufruf von: ExitBatch zurückgegeben wurde und die Testvariablendefinition ordnungsgemäß verworfen wurde, nachdem die Stapelverarbeitung beendet wurde.

C:\test>test.bat 
test=AFTER sub SETLOCAL 

C:\test>set test 
Environment variable test not defined 

C:\test> 

Die: ExitBatch-Routine kann in einen eigenen ExitBatch eingefügt werden.Bat-Skript und irgendwo in Ihrem PATH platziert, so dass es bequem von jedem Batch-Skript verwendet werden kann.

@echo off 
:ExitBatch - Cleanly exit batch processing, regardless how many CALLs 
if not exist "%temp%\ExitBatchYes.txt" call :buildYes 
call :CtrlC <"%temp%\ExitBatchYes.txt" 1>nul 2>&1 
:CtrlC 
cmd /c exit -1073741510 

:buildYes - Establish a Yes file for the language used by the OS 
pushd "%temp%" 
set "yes=" 
copy nul ExitBatchYes.txt >nul 
for /f "delims=(/ tokens=2" %%Y in (
    '"copy /-y nul ExitBatchYes.txt <nul"' 
) do if not defined yes set "yes=%%Y" 
echo %yes%>ExitBatchYes.txt 
popd 
exit /b 

Wichtige Update:

Es ist nun möglich, robust Ausnahme zu implementieren mit reinem Batch-Handling. Sie können nicht nur eine Ausnahme auslösen, die alle Stapelverarbeitungen von jeder CALL-Ebene aus beenden kann, sondern Sie können die Ausnahme auch auf einer höheren Ebene abfangen, spezielle Bereinigungscodes für die Ausnahmebehandlung ausführen und die Verarbeitung fortsetzen oder über einen anderen Wurf weitermachen! Weitere Informationen finden Sie unter Does Windows batch support exception handling?.

+0

Genial. Freut mich, dass Sie meine Entdeckung so schnell zu guter Arbeit machen konnten; gleicht die Verblüffung aus, die es mir ursprünglich verursacht hat. :-) –

+0

Nun, Sie haben eine Annahme verdient, Sir. – Gui13

+0

Schöne Lösung, für normale Fälle sauberer als meine. – jeb

20

Für eine gute Lösung finden Sie in der verbesserten Version Teil

Sie können einen Stapel an jedem beliebigen Punkt stoppen, auch innerhalb verschachtelter Funktionsaufrufe.

Sie müssen nur einen Syntaxfehler erstellen, z. B. mit einem leeren Block (), um die Fehlermeldung zu unterdrücken, sie kann in einem Aufruf ausgeführt werden, und der stderr des Aufrufs wird an nul umgeleitet.

@echo off 
setlocal enabledelayedexpansion 

rem Do something 
call :interactive_check 

rem Do something 
call :interactive_check 

goto :eof 

:::::::::::::::::::::::::: 
:interactive_check 
if errorlevel 1 (
    echo. 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    echo Error in compilation process... exiting 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    call :halt 1 
) ELSE (
    echo.Continuing to next step 
) 
goto :eof 

:: Sets the errorlevel and stops the batch immediately 
:halt 
call :__SetErrorLevel %1 
call :__ErrorExit 2> nul 
goto :eof 

:__ErrorExit 
rem Creates a syntax error, stops immediately 
() 
goto :eof 

:__SetErrorLevel 
exit /b %time:~-2% 
goto :eof 

2017-04-09 Verbesserte Version: Beenden Sie nur die aktuelle Partie, aber nicht der Anrufer Batch

Wie @dbenham erwähnt, gibt es eine neue Technik für die Ausnahmebehandlung, die auch verwendet werden können, um nur den aktuellen Stapel zu verlassen.

@echo off 
echo Do something, detecting some fatal error 
call :ExitBatch 3 
exit /b 

:ExitBatch [errorcode] - Exits only the current batch file, regardless how many CALLs 
set _errLevel=%1 
REM *** Remove all calls from the current batch from the call stack 
:popStack 
(
    (goto) 2>nul 
    setlocal DisableDelayedExpansion  
    call set "caller=%%~0" 
    call set _caller=%%caller:~0,1%% 
    call set _caller=%%_caller::=%% 
    if not defined _caller (
     REM callType = func 
     rem set _errLevel=%_errLevel% 
     goto :popStack 
    ) 
    (goto) 2>nul 
    endlocal 
    cmd /c "exit /b %_errLevel%" 
) 
echo NEVER REACHED 
exit /b 
+0

Coole Lösung :) Ich löste das Problem mit dem Vorschlag von atzz, aber falls jemand hier stolpert, werden Sie die Antwort sein. – Gui13

+1

Diese Lösung speichert Umgebungsänderungen nach SETLOCAL nicht ordnungsgemäß. Ich habe eine [saubere Lösung] (http://stackoverflow.com/a/25474648/1012053) entdeckt, die alle Änderungen nach SETLOCAL ordnungsgemäß verwirft. – dbenham

1

schlage ich folgende Lösung:

@echo off 

:: comment next line if you want to export any local variables in caller environment 
setlocal 

set FLAG=1 
rem Do something 
call :interactive_check 

set FLAG2=2 
rem Do something 
call :interactive_check 

goto :eof 

:interactive_check 
if errorlevel 1 (
    echo. 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    echo Error in compilation process... exiting 
    echo /!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\/!\ 
    (goto) 2>nul & endlocal & exit /b %ERRORLEVEL% 
) else (
    echo Continuing to next step 
) 
goto :eof 

Es Fehlercode von Befehl speichert die Fehler erzeugen. Wenn Sie Fehlercode an bestimmten Wert speichern möchten, dann ändern Sie die Zeile:

(goto) 2>nul & endlocal & exit /b YOUR_EXITCODE_HERE 

Ich mag keine Lösung mit Syntaxfehler (siehe jeb's post), weil es auch auch Anrufer der aktuellen Batch-Datei beendet.

1

Wenn Sie exit /b X verwenden, um die Funktion zu beenden, wird ERRORLEVEL auf den Wert X gesetzt. Sie können dann die ||conditional processing symbol verwenden, um einen anderen Befehl auszuführen, wenn ERRORLEVEL nach der call nicht Null ist.

@echo off 
setlocal 
call :myfunction PASS || goto :eof 
call :myfunction FAIL || goto :eof 
echo Execution never gets here 
goto :eof 

:myfunction 
    if "%1"=="FAIL" ( 
     echo myfunction: got a FAIL. Will exit. 
     exit /b 1 
    ) 
    echo myfunction: Everything is good. 
    exit /b 0 

Ausgabe von diesem Skript ist:

myfunction: Everything is good. 
myfunction: got a FAIL. Will exit. 
Verwandte Themen