Beenden Sie die Batch-Datei aus dem Unterprogramm

20

Wie kann ich eine Batch-Datei aus einem Unterprogramm heraus beenden?

Wenn ich den Befehl EXIT verwende, kehre ich einfach zu der Zeile zurück, in der ich die Unterroutine aufgerufen habe, und die Ausführung wird fortgesetzt.

Hier ist ein Beispiel:

@echo off
ECHO Quitting...
CALL :QUIT
ECHO Still here!
GOTO END

:QUIT
EXIT /B 1

:END
EXIT /B 0

Ausgabe:

Quitting...
Still here!

Aktualisieren:

Dies ist keine richtige Antwort, aber am Ende habe ich Folgendes getan:

@echo off
CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL
ECHO You shouldn't see this!
GOTO END

:SUBROUTINE_WITH_ERROR
ECHO Simulating failure...
EXIT /B 1

:HANDLE_FAIL
ECHO FAILURE!
EXIT /B 1

:END
ECHO NORMAL EXIT!
EXIT /B 0

Die Double-Pipe-Aussage von:

CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL

ist eine Abkürzung für:

CALL :SUBROUTINE_WITH_ERROR 
IF ERRORLEVEL 1 GOTO HANDLE_FAIL    

Ich würde immer noch gerne wissen, ob es eine Möglichkeit gibt, direkt aus einem Unterprogramm auszusteigen, anstatt den CALLER mit der Situation fertig werden zu lassen, aber dies erledigt zumindest die Aufgabe.


Update # 2: Beim Aufruf eines Unterprogramms aus einem anderen Unterprogramm, das wie oben beschrieben aufgerufen wurde, rufe ich aus dem Unterprogramm folgendermaßen auf:

CALL :SUBROUTINE_WITH_ERROR || EXIT /B 1

Auf diese Weise breitet sich der Fehler sozusagen bis zum "Haupt" aus. Der Hauptteil der Charge kann dann den Fehler mit der Fehlerbehandlungsroutine GOTO: FAILURE behandeln

Braun
quelle

Antworten:

21

Fügen Sie dies oben in Ihre Batch-Datei ein:

@ECHO OFF
SETLOCAL

IF "%selfWrapped%"=="" (
  REM this is necessary so that we can use "exit" to terminate the batch file,
  REM and all subroutines, but not the original cmd.exe
  SET selfWrapped=true
  %ComSpec% /s /c ""%~0" %*"
  GOTO :EOF
)

Dann können Sie einfach anrufen:

  • EXIT [errorLevel] Wenn Sie die gesamte Datei beenden möchten
  • EXIT /B [errorLevel] um das aktuelle Unterprogramm zu verlassen
  • GOTO :EOF um das aktuelle Unterprogramm zu verlassen
Merlyn Morgan-Graham
quelle
+1 für die tatsächliche ErwähnungGOTO :EOF
afrazier
1
Sehr schön. Ich habe eine kleine Änderung vorgenommen, wies %~0auf die Variable statt true: if not "%selfwrapped%"=="%~0" ( set selfwrapped=%~0 .... ). Auf diese Weise können Sie denselben Trick in mehreren Stapelskripten verwenden, die sich gegenseitig aufrufen.
GolezTrol
Dies ist eine großartige Lösung. Glaubst du, es ist eine Bearbeitung wert, um zu erklären, wie es funktioniert? Es dauerte eine Minute alles auszupacken , dass und erkennt , dass es tatsächlich nur die Batch - Datei aufrufe ( %~0) mit allen Argumenten ( %*) aus einer verschachtelten cmd.exe, und die /sverwendet wird , um die Art und Weise , die zu steuern %ComSpec%Argument Griff die doppelten Anführungszeichen um die Anruf.
Sean
@ Sean Ich finde, Kürze ist für die meisten Menschen nützlicher. In den sieben Jahren, seit ich es geschrieben habe, wurden keine weiteren Dokumente mehr angefragt, daher scheint es nicht sehr gefragt zu sein. Ich denke auch, dass es einen gewissen Wert hat, wenn Leute Dinge selbst nachschlagen und Dokumente nicht nachahmen / fragmentieren. Aber wenn ein paar Leute mehr fragen, könnte ich vielleicht etwas hinzufügen. Es ist auch eine CW, so dass Sie auch eine
Merlyn Morgan-Graham
3

Wie wäre es mit dieser kleinen Anpassung?

@echo off
ECHO Quitting...
CALL :QUIT
:: The QUIT subroutine might have set the error code so let's take a look.
IF ERRORLEVEL 1 GOTO :EOF
ECHO Still here!
GOTO END

:QUIT
EXIT /B 1

:END
EXIT /B 0

Ausgabe:

Quitting...

Technisch gesehen verlässt dies das Unterprogramm nicht. Vielmehr prüft es einfach das Ergebnis des Unterprogramms und ergreift von dort aus Maßnahmen.

JMD
quelle
2
Danke, das würde sicherlich die Arbeit erledigen, und wenn ich keine bessere Antwort finden kann, muss ich das tun. Ich möchte diese Zeile jedoch lieber nicht nach jedem CALL in meine lange und komplexe Batch-Datei einfügen.
Brown
1

Wenn Sie nicht von der Prozedur zurückkehren möchten, verwenden Sie nicht call: stattdessen goto.

@echo off
ECHO Quitting...
GOTO :QUIT
ECHO Will never be there!
GOTO END

:QUIT
EXIT /B 1

:END
EXIT /B 0
Dolmen
quelle
Der Punkt der Frage ist, wie man es von Unterprogrammen aus macht (dh mit Hilfe von Aufrufen), damit dies nicht beantwortet wird.
Steve Crane
1

Ich habe die Fehlerbehandlung in meine Batch-Dateien eingefügt. Sie können Fehlerbehandlungsroutinen wie diese aufrufen:

CALL :WARNING "This is" "an important" "warning."

Und hier ist das Ende der Batch-Datei:

::-------------------------------------------------------------------
::  Decisions
::-------------------------------------------------------------------
:INFO
IF "_DEBUG"=="true" (
  ECHO INFO: %~1
  IF NOT "%~2"=="" ECHO          %~2
  IF NOT "%~3"=="" ECHO          %~3
)
EXIT /B 0
:WARNING
ECHO WARNING: %~1
IF NOT "%~2"=="" ECHO          %~2
IF NOT "%~3"=="" ECHO          %~3
EXIT /B 0
:FAILURE
ECHO FAILURE: %~1
IF NOT "%~2"=="" ECHO          %~2
IF NOT "%~3"=="" ECHO          %~3
pause>nul
:END
ECHO Closing Server.bat script
FOR /l %%a in (5,-1,1) do (TITLE %TITLETEXT% -- closing in %%as&PING.exe -n 2 -w 1 127.0.0.1>nul)
Djangofan
quelle
1

Dadurch wird der aktuelle Kontext und ein übergeordneter Kontext beendet (dh, wenn er in einem calleinstufigen Subroutinenskript ausgeführt wird, wird er beendet):

(goto) 2>nul || exit /b

Oder, wenn Sie Fehlerlevel 0 benötigen:

(goto) 2>nul || (
    type nul>nul
    exit /b
)

Grundsätzlich wird (goto) 2>nuldie Fehlerebene auf 1 gesetzt (ohne dass ein Fehler ausgegeben wird) und die Ausführung an den übergeordneten Kontext und den Code zurückgegeben, nachdem die doppelte Pipe im übergeordneten Kontext ausgeführt wurde. type nul>nulsetzt errorlevel auf 0

UPD:

Um die Ausführung mehr als zweimal hintereinander zurückzugeben, verketten Sie mehrere (goto) 2>nul ||wie folgt:

(goto) 2>nul || (goto) 2>nul || (goto) 2>nul || (
    type nul>nul
    exit /b
)

Hier ist eine rekursive Subroutine, mit der der Kontext eine variable Anzahl von Malen zurückgegeben werden kann:

:Kill
(goto) 2>nul || (
    set /a depth=%1-1
    if %1 GEQ 1 (
        call:Kill !depth!
    )
    (goto) 2>nul || (type nul>nul)
)

Beim Aufruf von einer rekursiven Funktion:

@echo off
setlocal EnableDelayedExpansion
call:Recurs 5
echo This won't be printed
exit /b

:Recurs
set /a ri+=1
echo %ri%
if %ri% LSS %1 (
    call:Recurs %1
)
echo This will be printed only once
call:Kill %1
exit /b

die Ausgabe wird sein:

1
2
3
4
5
This will be printed only once
HYBRIDWESEN
quelle