Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit

Batch - for-Schleife vorzeitig beenden

Frage Entwicklung Batch & Shell

Mitglied: NeonZero

NeonZero (Level 1) - Jetzt verbinden

29.08.2008, aktualisiert 18.10.2012, 21371 Aufrufe, 9 Kommentare

Hallo.

Ich möchte eine for-Schleife vorzeitig beenden und suche nach Ideen dafür. Hier der Code, der verdeutlichen soll, was ich meine:
01.
for %%a in (a b c d e) do (  
02.
  echo %%a 
03.
  if "%%a" == "c" break_loop 
04.
05.
------------------------------------------- 
06.
gewünschte Ausgabe:	 
07.
08.
09.
c
Lösung 1: Eine mögliche Lösung wäre der folgende Code:
01.
::Der folgende Code wurde nach einem Hinweis von bastla (siehe seinen Beitrag weiter unten) 
02.
::derart angepasst, dass hier auf setlocal EnableDelayedExpansion verzichtet werden kann. Thx 
03.
 
04.
for %%a in (a b c d e) do if not defined _break ( 
05.
  echo %%a 
06.
  if "%%a" == "c" set _break=now 
07.
)
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:
01.
call :FncMyForLoop 
02.
goto :EOF 
03.
 
04.
:FncMyForLoop 
05.
  for %%a in (a b c d e) do ( 
06.
    echo %%a 
07.
    if "%%a" == "c" exit /b 0 
08.
09.
 exit /b 1
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.
01.
for %%a in (a b c d e) do (  
02.
  echo %%a 
03.
  if "%%a" == "c" goto :Weiter 
04.
05.
:Weiter 
06.
echo Hier geht es weiter ...
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
Mitglied: ahe
29.08.2008 um 17:36 Uhr
Hallo,

reicht dir das vielleicht schon:

01.
@echo off 
02.
for %%a in (a b c d e) do (   
03.
	echo %%a  
04.
	if "%%a" == "c" exit /b  
05.
) 
Die Ausgabe am Prompt sieht dann so aus:
a
b
c

mfg
Axel
Bitte warten ..
Mitglied: NeonZero
29.08.2008 um 17:46 Uhr
Hallo Axel und danke für Deine Antwort.

Die Idee ist nicht schlecht, hat nur leider den Nachteil, dass dadurch umgehend die Batch beendet wird. Ziel ist es nicht, die obige Ausgabe zu erhalten, sondern eine allgemein verwendbare Möglichkeit zu finden, die for-Schleife (und nicht die Batch) vorzeitig zu beenden. Die Zielstellung habe ich offensichtlich nicht eindeutig formuliert. Mein Fehler. Sorry.

Bye, nz
Bitte warten ..
Mitglied: ahe
29.08.2008 um 17:59 Uhr
Ach so... mmh, das gehe doch zu einer Sprungmarke... danach kannst Du auch noch andere Dinge ausführen...

01.
@echo off 
02.
for %%a in (a b c d e diedeldum gnuffz c c d d) do (   
03.
	echo %%a  
04.
	if "%%a" == "c" goto WEITER  
05.
)  
06.
 
07.
:WEITER 
08.
echo es geht weiter 
09.
goto DA 
10.
 
11.
:DA 
12.
echo Jetzt bin ich da 
13.
 
14.
:END 
15.
echo Laeuft bis zum Ende 
16.
echo. 
17.
echo und tschuess...
mfg
Axel
Bitte warten ..
Mitglied: NeonZero
29.08.2008 um 18:22 Uhr
Ein schöner Ansatz. Danke. Ich habe ihn oben als Nachtrag aufgelistet.

Bye, nz
Bitte warten ..
Mitglied: bastla
29.08.2008, aktualisiert 18.10.2012
Hallo NeonZero!

Eine etwas abgewandelte Version Deiner ersten Variante kommt ohne "delayedExpansion" aus:
01.
@echo off & setlocal 
02.
set done= 
03.
for %%a in (a b c d e) do if not defined done ( 
04.
  echo %%a 
05.
  if "%%a"=="c" set done=break 
06.
)
Einfach aus der Schleife herauszuspringen ist zwar auch möglich, aber von Biber nicht empfohlen ...

Grüße
bastla
Bitte warten ..
Mitglied: NeonZero
29.08.2008 um 21:12 Uhr
Hallo bastla.

Das ist ein guter Vorschlag. Ich habe den Code oben mit einem Hinweis auf Deinen Beitrag entsprechend angepaßt. Danke.

Zum verlinkten Beitrag: " Das "Verlassen" einer FOR-Anweisung ist eigentlich vom sympathischen Weltmarktführer nicht vorgesehen, geschweige denn zugesichert. " (Biber)

@Biber (falls Du mitliest): Woher stammt diese Information und mit welche Auswirkungen ist zu rechnen? Hast Du (oder sonst jemand) diesbezüglich eigene Erfahrungen gemacht?

Bye, nz
Bitte warten ..
Mitglied: bastla
29.08.2008 um 22:30 Uhr
Hallo NeonZero!

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:
01.
for /f "delims=" %%i in ('findstr /c:"bestimmte Information" "D:\Große Datei.txt"') do ...
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
Bitte warten ..
Mitglied: Biber
30.08.2008 um 01:50 Uhr
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
Bitte warten ..
Mitglied: NeonZero
30.08.2008 um 09:27 Uhr
Hallo Biber.

Das, was Du beschrieben hast, ist ein grundsätzliches Problem. Wenn mir Konsole-Programme, die in C geschrieben wurden, während der Entwicklung abgestürzt sind, gab es ähnliche Effekte, gerade was das Environment anbelangt. Diese traten aber nie auf, wenn das Programm durch lief.

Ein für die cmd.exe unerwarteter Absturz einer Batch oder eines beliebigen Konsoleprogramms kann schlimme Auswirkungen haben. Denn die Konsole besteht danach weiter. Sie ist so rudimentär, dass sie – anders als bei einer Windows-Applikation – hierfür keine Schutzmechanismen anbietet (einmal abgesehen von konzeptionellen Ansätzen wie start, oder setlocal, die die Arbeitsweise einschränken oder nur bedingt „schützen“ können). Ein Konsoleprogramm, das danach in derselben Konsole aufgerufen wird, läuft daher in einer nahezu undefinierten Umgebung. Deshalb ist es hier umso wichtiger, Programmierfehler zu vermeiden, die einen Absturz zur Folge haben könnten. Das gilt gleichermaßen für Batches, C-Programme, oder was auch immer.

Verhindern kann man dieses Verhalten, indem man start verwendet, also jedes Konsoleprogramm in einer eigenen cmd.exe-Umgebung ausführt. Dann muss man sich aber darüber im Klaren sein, das die Konsoleprogramme so keinen Einfluss mehr auf die Umgebung des Aufrufers nehmen können (auch eine Batch ist dann nicht mehr in der Lage, eine Variable der ursprünglichen Konsole direkt zu ändern).

Wenn MS die Stack-Behandlung der cmd.exe nicht vollkommen verbockt hat, sollten auch bei Batches sämtliche Sprünge aus Schleifen / Funktionen / Blöcken, gleich welcher Art, korrekt abgearbeitet und zum Ende des Programms sauber abgeschlossen werden. Das bedeutet z.B. auch, dass die oben erfragte Datei, die in der for-Schleife geöffnet wurde, ordentlich geschlossen wird (inkl. Freigabe sämtlicher Handle, etc.), sobald die Batch ein reguläres Ende findet. Dann nämlich werden auch sämtliche for-Schleifen, aus die man herausgesprungen ist, regulär beendet (so sollte es zumindest sein).

Daher nun meine Frage, ob solche Probleme auch dann beobachtet wurden, wenn die Batch nicht an einem für die cmd.exe unerwarteten Punkt abgestürzt ist. Denn wenn man Probleme mit dem Environment hat, obgleich die Batch ohne Programmierfehler durch lief, ist das ein sicheres Zeichen dafür, dass die cmd.exe tatsächlich unsauber arbeitet und solche Sprünge nicht verkraftet.

Bye, nz
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(8)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
Batch & Shell
gelöst Batch Problem bei einer For Schleife (2)

Frage von Juergen42 zum Thema Batch & Shell ...

Batch & Shell
Batch: Variable Expansion in einer FOR-Schleife (9)

Frage von .Sessl zum Thema Batch & Shell ...

Batch & Shell
gelöst Batch Probleme mit Dateipfaden in for-Schleife (1)

Frage von Jonas1806 zum Thema Batch & Shell ...

Batch & Shell
gelöst Batch Schleife als FOR-SCHLEIFE (2)

Frage von mp2711 zum Thema Batch & Shell ...

Heiß diskutierte Inhalte
Microsoft
Ordner mit LW-Buchstaben versehen und benennen (21)

Frage von Xaero1982 zum Thema Microsoft ...

Netzwerkmanagement
gelöst Anregungen, kleiner Betrieb, IT-Umgebung (18)

Frage von Unwichtig zum Thema Netzwerkmanagement ...

Windows Update
Treiberinstallation durch Windows Update läßt sich nicht verhindern (17)

Frage von liquidbase zum Thema Windows Update ...