Batch - for-Schleife vorzeitig beenden
Hallo.
Ich möchte eine for-Schleife vorzeitig beenden und suche nach Ideen dafür. Hier der Code, der verdeutlichen soll, was ich meine:
Lösung 1: Eine mögliche Lösung wäre der folgende Code:
Dieser Ansatz hat den Nachteil, dass d und e weiterhin durchlaufen werden, auch wenn der Block dabei nicht abgearbeitet wird. Will man mithilfe einer solchen for-Schleife z.B. eine bestimmte Information aus einer großen Datei holen, so werden – nachdem man die Information gefunden hat – auch die darauf folgenden Zeilen eingelesen. Und für jede Zeile wird die if-Abfrage abgearbeitet, was je nach Größe der Datei unnötig viel Zeit in Anspruch nimmt.
Lösung 2: Das zuvor beschriebene Problem lässt sich mit dem folgenden Code umgehen:
Der Code hat gleichzeitig den Vorteil, dass man anhand des Errorlevels erkennen kann, ob „c“ gefunden wurde, oder nicht (nach dem call-Aufruf: if %errorlevel% == 1 echo c wurde nicht gefunden! ).
Diese Lösung ist allerdings sehr umständlich, da man für jede for-Schleife eine eigene Funktion schreiben müsste. Viel besser wäre es, wenn man die for-Schleife direkt zu einem Abbruch zwingen kann. Um genau solche Lösungsansätze geht es in diesem Thread.
Bye, nz
Lösung 3: Benutzer ahe hat weiter unten den folgenden Ansatz eingebracht.
Eine noch idealere Lösung wäre es, wenn man die for-Schleife einfach beenden könnte, ohne den Umweg über die Sprungmarke zu gehen. Andernfalls müsste man für jede dieser for-Schleifen eine eigene Sprungmarke setzen (was zugegebenermaßen ein eher kleines Übel wäre). Hat jemand dafür eine Idee? –- NeonZero 29.08.2008 18:19
Ich möchte eine for-Schleife vorzeitig beenden und suche nach Ideen dafür. Hier der Code, der verdeutlichen soll, was ich meine:
for %%a in (a b c d e) do (
echo %%a
if "%%a" == "c" break_loop
)
-------------------------------------------
gewünschte Ausgabe:
a
b
c
::Der folgende Code wurde nach einem Hinweis von bastla (siehe seinen Beitrag weiter unten)
::derart angepasst, dass hier auf setlocal EnableDelayedExpansion verzichtet werden kann. Thx
for %%a in (a b c d e) do if not defined _break (
echo %%a
if "%%a" == "c" set _break=now
)
Lösung 2: Das zuvor beschriebene Problem lässt sich mit dem folgenden Code umgehen:
call :FncMyForLoop
goto :EOF
:FncMyForLoop
for %%a in (a b c d e) do (
echo %%a
if "%%a" == "c" exit /b 0
)
exit /b 1
Diese Lösung ist allerdings sehr umständlich, da man für jede for-Schleife eine eigene Funktion schreiben müsste. Viel besser wäre es, wenn man die for-Schleife direkt zu einem Abbruch zwingen kann. Um genau solche Lösungsansätze geht es in diesem Thread.
Bye, nz
Lösung 3: Benutzer ahe hat weiter unten den folgenden Ansatz eingebracht.
for %%a in (a b c d e) do (
echo %%a
if "%%a" == "c" goto :Weiter
)
:Weiter
echo Hier geht es weiter ...
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 95668
Url: https://administrator.de/contentid/95668
Ausgedruckt am: 21.11.2024 um 23:11 Uhr
11 Kommentare
Neuester Kommentar
Ach so... mmh, das gehe doch zu einer Sprungmarke... danach kannst Du auch noch andere Dinge ausführen...
mfg
Axel
@echo off
for %%a in (a b c d e diedeldum gnuffz c c d d) do (
echo %%a
if "%%a" == "c" goto WEITER
)
:WEITER
echo es geht weiter
goto DA
:DA
echo Jetzt bin ich da
:END
echo Laeuft bis zum Ende
echo.
echo und tschuess...
mfg
Axel
Hallo NeonZero!
Eine etwas abgewandelte Version Deiner ersten Variante kommt ohne "delayedExpansion" aus:
Einfach aus der Schleife herauszuspringen ist zwar auch möglich, aber von Biber nicht empfohlen ...
Grüße
bastla
Eine etwas abgewandelte Version Deiner ersten Variante kommt ohne "delayedExpansion" aus:
@echo off & setlocal
set done=
for %%a in (a b c d e) do if not defined done (
echo %%a
if "%%a"=="c" set done=break
)
Grüße
bastla
Hallo NeonZero!
Weil Du oben zur Variante mit der "Schalter"-Variable meintest:
Je nach Verwendungszweck kann es dann noch sinnvoll sein, die Zeilennummern (für einen späteren "direkten" Zugriff) mit angeben zu lassen ("/n") und durch "Hintereinanderschalten" mehrerer Suchvorgänge die Anzahl der tatsächlich per Schleife zu bearbeitenden Zeilen zu reduzieren ...
Grüße
bastla
Weil Du oben zur Variante mit der "Schalter"-Variable meintest:
Dieser Ansatz hat den Nachteil, dass d und e weiterhin durchlaufen werden, auch wenn der Block dabei nicht abgearbeitet wird. Will man mithilfe einer solchen for-Schleife z.B. eine bestimmte Information aus einer großen Datei holen, so werden – nachdem man die Information gefunden hat – auch die darauf folgenden Zeilen eingelesen. Und für jede Zeile wird die if-Abfrage abgearbeitet, was je nach Größe der Datei unnötig viel Zeit in Anspruch nimmt.
Um eine bestimmte Information aus einer großen Datei zu holen, wird sich oftmals "findstr" anbieten, etwa:for /f "delims=" %%i in ('findstr /c:"bestimmte Information" "D:\Große Datei.txt"') do ...
Grüße
bastla
Moin NeonZero,
zu dem nicht empfohlenen (und nicht vorgesehenen) Verlassen einer FOR-Schleife.
M$ hat in den (relativ umfangreichen) Dokumentationen zu FOR und CALL und GOTO nie erwähnt, ob und welche der FOR-Anweisungen gefahrlos unvollendet bleiben können.
Wir reden doch hier (nur zur Erinnerung) von einem Befehlsinterpreter namens CMD.exe, der eigentlich jeden vom CMD-Prompt abgesetzten Befehl xy (oder auch einen Batch abc.bat) am Dienstag um 13h exakt so interpretieren sollte wie am Freitag um 04:23h.
Aber schon durch einen Batch-Programmabbruch (z.B. ein Syntaxfehler) in einem Batch mit einigen der "neueren" Sprachelemente wie
- Setlocal/Endlocal
- EnableExtensions/EnableDelayedExpansion bzw. der Disable-Gegenstücke...
... merkst Du sehr schnell, dass die CMD.exe sehr empfindlich auf geöffnete und nicht geschlossene Klammern (das sind diese Elemnte ja) reagiert.
Plötzlich befindest Du Dich -aus eimem Batch herausgeflogen- am CMD-Prompt und das "Echo ist OFF" - der häufigste und harmloseste Fall.
Oder aber Du bist am CMD-Prompt in einem Zustand, in dem Du lokale (setlocal) Variablen anlegen kannst - was eigentlich nur im Batch und nie am CMD-Prompt gehen sollte.
Nun sind seit W2000 noch ein paar lustige FOR-Anweisungsvarianten dazugekommen - zur "schon immer" vorhandenden For-ein-paar-Elemente-durchwackel-Anweisung sind rekursive Konstrukte (FOR /R) und vor allem FOR-Anweisungen dazugekommen, die Files/Filehandles/Verzeichnisstrukturen/Fremdfunktionen nutzen/öffnen/anfordern.
Was passiert denn mit einer für eine For/F-Anweisung zum Lesen geöffneten Datei, wenn das Lesen/die FOR-Anweisung niemals endet? Was passiert in einer rekursiv angelegten FOR/R-Anweisung, wenn Du das Wurzelelement löscht? Oder in einer FOR/D-Anweisung? Wie viele Stacks/Caches/Buffers/Pushs und Pops hat denn die CMD.exe reserviert oder allokiert und wieviele freigegeben bei einer unvollendeten Schleife?
Das mag testen wer will, aber in Batchabläufen, die im produktiven Umfeld laufen (z.B. zur Datensicherung oder Update-Gewährleistung) möchte ich NICHTS riskieren, das Seiteneffekte hervorrufen könnte. Oder eben dazu führt, dass sich ein und derselbe Batch je nachdem was vorher so gelaufen ist, am Dienstag um 13h anders verhält als Freitags morgens.
...ich verhalte mich auch montags nicht anders as mittwochs...
Grüße
Biber
zu dem nicht empfohlenen (und nicht vorgesehenen) Verlassen einer FOR-Schleife.
M$ hat in den (relativ umfangreichen) Dokumentationen zu FOR und CALL und GOTO nie erwähnt, ob und welche der FOR-Anweisungen gefahrlos unvollendet bleiben können.
Wir reden doch hier (nur zur Erinnerung) von einem Befehlsinterpreter namens CMD.exe, der eigentlich jeden vom CMD-Prompt abgesetzten Befehl xy (oder auch einen Batch abc.bat) am Dienstag um 13h exakt so interpretieren sollte wie am Freitag um 04:23h.
Aber schon durch einen Batch-Programmabbruch (z.B. ein Syntaxfehler) in einem Batch mit einigen der "neueren" Sprachelemente wie
- Setlocal/Endlocal
- EnableExtensions/EnableDelayedExpansion bzw. der Disable-Gegenstücke...
... merkst Du sehr schnell, dass die CMD.exe sehr empfindlich auf geöffnete und nicht geschlossene Klammern (das sind diese Elemnte ja) reagiert.
Plötzlich befindest Du Dich -aus eimem Batch herausgeflogen- am CMD-Prompt und das "Echo ist OFF" - der häufigste und harmloseste Fall.
Oder aber Du bist am CMD-Prompt in einem Zustand, in dem Du lokale (setlocal) Variablen anlegen kannst - was eigentlich nur im Batch und nie am CMD-Prompt gehen sollte.
Nun sind seit W2000 noch ein paar lustige FOR-Anweisungsvarianten dazugekommen - zur "schon immer" vorhandenden For-ein-paar-Elemente-durchwackel-Anweisung sind rekursive Konstrukte (FOR /R) und vor allem FOR-Anweisungen dazugekommen, die Files/Filehandles/Verzeichnisstrukturen/Fremdfunktionen nutzen/öffnen/anfordern.
Was passiert denn mit einer für eine For/F-Anweisung zum Lesen geöffneten Datei, wenn das Lesen/die FOR-Anweisung niemals endet? Was passiert in einer rekursiv angelegten FOR/R-Anweisung, wenn Du das Wurzelelement löscht? Oder in einer FOR/D-Anweisung? Wie viele Stacks/Caches/Buffers/Pushs und Pops hat denn die CMD.exe reserviert oder allokiert und wieviele freigegeben bei einer unvollendeten Schleife?
Das mag testen wer will, aber in Batchabläufen, die im produktiven Umfeld laufen (z.B. zur Datensicherung oder Update-Gewährleistung) möchte ich NICHTS riskieren, das Seiteneffekte hervorrufen könnte. Oder eben dazu führt, dass sich ein und derselbe Batch je nachdem was vorher so gelaufen ist, am Dienstag um 13h anders verhält als Freitags morgens.
...ich verhalte mich auch montags nicht anders as mittwochs...
Grüße
Biber
Microsoft beschreibt nirgends, dass eine for-Schleife nicht mit einem GOTO abgebrochen werden darf. Man kann also annehmen, dass dies erlaubt ist. Tatsächlich scheint intern der Interpreter sauber aufzuräumen, jedenfalls hatte ich mit einem reinen Abbruch noch nie Probleme auch in komplexen Scripten. Und undefinierte Ängste sind eh ein Hinweis-, aber kein Ratgeber. Erlaubt ist also:
Diese meine Einschätzung wird gestützt durch die Tatsache, dass Sprünge, die nicht stumpf alle Ebenen verlassen, explizit abgefangen werden. Das folgende führt noch vor der echo-bedingten Anzeige zu einem '")" kann syntaktisch an dieser Stelle nicht verarbeitet werden.':
Tom
for (irgendetwas) do (
for (irgendetwasanderes) do (
goto Gefunden
)
)
:Gefunden
Diese meine Einschätzung wird gestützt durch die Tatsache, dass Sprünge, die nicht stumpf alle Ebenen verlassen, explizit abgefangen werden. Das folgende führt noch vor der echo-bedingten Anzeige zu einem '")" kann syntaktisch an dieser Stelle nicht verarbeitet werden.':
echo on
for (irgendetwas) do (
for (irgendetwasanderes) do (
goto Absturz
)
:Absturz << Diese Zeile darf nicht hier stehen
)
Tom
Na ja, MS hat schon am Interpreter in den letzten Jahren deutlich gedreht, manche Einstellungen verändert, manche Parameter bei Befehlen hinzugefügt, etc., so dass manche Skripte nicht mehr so laufen, wie noch vor 10 Jahren...
(wenn ich alleine an die Datum/Uhrzeit Verarbeitung oder sprachspez. Dinge denke...)
Eigentlich wird auch immer mehr der Fokus auf die Powershell gelegt, als in den "alten" Kommandointerpreter... der wird nur noch notgedrungen, vermutlich aus Kompatibilitätsgründen, mitgezogen...
mfg
Axel
. . . da fühlt man sich doch tatsächlich wieder jünger, wenn man seine alten Beiträge nach ca. 10 Jahren mal wieder sieht...
Ist fast wie ein Schulfreund nach 20-30 Jahren zu sehen und soger wiederzuerkennen...
(wenn ich alleine an die Datum/Uhrzeit Verarbeitung oder sprachspez. Dinge denke...)
Eigentlich wird auch immer mehr der Fokus auf die Powershell gelegt, als in den "alten" Kommandointerpreter... der wird nur noch notgedrungen, vermutlich aus Kompatibilitätsgründen, mitgezogen...
mfg
Axel
. . . da fühlt man sich doch tatsächlich wieder jünger, wenn man seine alten Beiträge nach ca. 10 Jahren mal wieder sieht...
Ist fast wie ein Schulfreund nach 20-30 Jahren zu sehen und soger wiederzuerkennen...