Wir haben Experimente durchgeführt, um die Grammatik von Batch-Skripten zu untersuchen. Wir haben auch Unterschiede zwischen Batch- und Befehlszeilenmodus untersucht.
Batch Line Parser:
Hier ist eine kurze Übersicht über die Phasen im Batch-File-Line-Parser:
Phase 0) Zeile lesen:
Phase 1) Prozentuale Expansion:
Phase 2) Verarbeiten Sie Sonderzeichen, tokenisieren Sie und erstellen Sie einen zwischengespeicherten Befehlsblock: Dies ist ein komplexer Prozess, der von Anführungszeichen, Sonderzeichen, Token-Trennzeichen und Caret-Escapezeichen beeinflusst wird.
Phase 3) Echo der analysierten Befehle Nur dann, wenn der Befehlsblock nicht mit begonnen @
hat und ECHO zu Beginn des vorherigen Schritts eingeschaltet war.
Phase 4) FOR- %X
Variablenerweiterung: Nur wenn ein FOR-Befehl aktiv ist und die Befehle nach DO verarbeitet werden.
Phase 5) Verzögerte Erweiterung: Nur wenn die verzögerte Erweiterung aktiviert ist
Phase 5.3) Rohrbearbeitung: Nur wenn sich Befehle auf beiden Seiten einer Rohrleitung befinden
Phase 5.5) Umleitung ausführen:
Phase 6) CALL-Verarbeitung / Caret-Verdopplung: Nur wenn das Befehlstoken CALL ist
Phase 7) Ausführen: Der Befehl wird ausgeführt
Hier sind Details für jede Phase:
Beachten Sie, dass die unten beschriebenen Phasen nur ein Modell für die Funktionsweise des Batch-Parsers sind. Die tatsächlichen cmd.exe-Interna spiegeln diese Phasen möglicherweise nicht wider. Dieses Modell ist jedoch effektiv bei der Vorhersage des Verhaltens von Batch-Skripten.
Phase 0) Zeile lesen: Lesen Sie zuerst die Eingabezeile durch <LF>
.
- Beim Lesen einer Zeile, die als Befehl analysiert werden soll, wird
<Ctrl-Z>
(0x1A) als gelesen<LF>
(LineFeed 0x0A)
- Wenn GOTO oder CALL beim Lesen nach einem: -Label Zeilen lesen
<Ctrl-Z>
, wird es als sich selbst behandelt - es wird nicht in konvertiert<LF>
Phase 1) Prozentuale Expansion:
- Ein Doppel
%%
wird durch ein Einzel ersetzt%
- Erweiterung der Argumente (
%*
, %1
, %2
, etc.)
- Erweiterung von
%var%
, wenn var nicht existiert, ersetzen Sie es durch nichts
- Die Linie wird zunächst
<LF>
nicht innerhalb der %var%
Erweiterung abgeschnitten
- Für eine vollständige Erklärung lesen Sie die erste Hälfte von dbenham. Gleicher Thread: Prozentphase
Phase 2) Verarbeiten von Sonderzeichen, Tokenisieren und Erstellen eines zwischengespeicherten Befehlsblocks: Dies ist ein komplexer Prozess, der von Anführungszeichen, Sonderzeichen, Token-Trennzeichen und Caret-Escapezeichen beeinflusst wird. Was folgt, ist eine Annäherung an diesen Prozess.
Es gibt Konzepte, die in dieser Phase wichtig sind.
- Ein Token ist einfach eine Zeichenfolge, die als Einheit behandelt wird.
- Token werden durch Token-Trennzeichen getrennt. Die Standard-Token-Begrenzer sind
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
und <0xFF>
aufeinanderfolgende Token-Begrenzer werden als eins behandelt. Zwischen den Token-Begrenzern befinden sich keine leeren Token
- Innerhalb einer Zeichenfolge in Anführungszeichen gibt es keine Token-Trennzeichen. Die gesamte Zeichenfolge in Anführungszeichen wird immer als Teil eines einzelnen Tokens behandelt. Ein einzelnes Token kann aus einer Kombination von Zeichenfolgen in Anführungszeichen und Zeichen ohne Anführungszeichen bestehen.
Die folgenden Zeichen können in dieser Phase je nach Kontext eine besondere Bedeutung haben: <CR>
^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
<0xFF>
Schauen Sie sich jedes Zeichen von links nach rechts an:
- Wenn
<CR>
dann entfernen Sie es, als ob es nie da wäre (außer für seltsames Umleitungsverhalten )
- Bei einem Caret (
^
) wird das nächste Zeichen maskiert und das entkommende Caret entfernt. Entkommene Zeichen verlieren jede besondere Bedeutung (außer <LF>
).
- Wenn ein Zitat (
"
), schalten Sie das Anführungszeichen um. Wenn das Anführungszeichen aktiv ist, dann nur "
und <LF>
sind speziell. Alle anderen Zeichen verlieren ihre spezielle Bedeutung, bis das nächste Anführungszeichen die Anführungszeichenflagge ausschaltet. Es ist nicht möglich, sich dem Schlusszitat zu entziehen. Alle in Anführungszeichen gesetzten Zeichen befinden sich immer im selben Token.
<LF>
schaltet immer die Anführungszeichenflagge aus. Andere Verhaltensweisen variieren je nach Kontext, aber Anführungszeichen ändern niemals das Verhalten von <LF>
.
- Entkam
<LF>
<LF>
wird abgestreift
- Das nächste Zeichen wird maskiert. Wenn am Ende des Zeilenpuffers, wird die nächste Zeile von den Phasen 1 und 1.5 gelesen und verarbeitet und an die aktuelle angehängt, bevor das nächste Zeichen ausgeblendet wird. Wenn das nächste Zeichen ist
<LF>
, wird es als Literal behandelt, was bedeutet, dass dieser Prozess nicht rekursiv ist.
<LF>
Nicht entgangen, nicht in Klammern
<LF>
wird entfernt und das Parsen der aktuellen Zeile wird beendet.
- Alle verbleibenden Zeichen im Zeilenpuffer werden einfach ignoriert.
- In
<LF>
einem FOR IN-Klammerblock nicht
entkommen
<LF>
wird in a umgewandelt <space>
- Wenn am Ende des Zeilenpuffers, wird die nächste Zeile gelesen und an die aktuelle angehängt.
- In
<LF>
einem in Klammern gesetzten Befehlsblock nicht
entkommen
<LF>
wird in konvertiert <LF><space>
und das <space>
wird als Teil der nächsten Zeile des Befehlsblocks behandelt.
- Wenn am Ende des Zeilenpuffers, wird die nächste Zeile gelesen und an das Leerzeichen angehängt.
- Wenn eines der Sonderzeichen
&
|
<
oder >
, teilen Sie die Zeile an dieser Stelle, um Pipes, Befehlsverkettung und Umleitung zu verarbeiten.
- Im Falle eines Rohres (
|
) ist jede Seite ein separater Befehl (oder Befehlsblock), der in Phase 5.3 eine spezielle Behandlung erhält
- Im Fall von
&
, &&
oder ||
Befehlsverkettung, wobei jede Seite der Verkettung wird als separater Befehl behandelt.
- Im Fall von
<
, <<
, >
, oder >>
Umleitung wird die Umleitungs Klausel geparst, vorübergehend entfernt und dann bis zum Ende des aktuellen Befehls angehängt. Eine Umleitungsklausel besteht aus einer optionalen Dateihandle-Ziffer, dem Umleitungsoperator und dem Umleitungsziel-Token.
- Wenn das Token vor dem Umleitungsoperator eine einzelne nicht entkoppelte Ziffer ist, gibt die Ziffer das umzuleitende Dateihandle an. Wenn das Handle-Token nicht gefunden wird, wird standardmäßig 1 (stdout) und standardmäßig 0 (stdin) ausgegeben.
- Wenn das allererste Token für diesen Befehl (vor dem Verschieben der Umleitung zum Ende) mit beginnt
@
, hat das @
eine besondere Bedeutung. ( @
ist in keinem anderen Kontext etwas Besonderes)
- Das Special
@
wird entfernt.
- Wenn ECHO eingeschaltet ist, werden dieser Befehl zusammen mit den folgenden verketteten Befehlen in dieser Zeile vom Phase-3-Echo ausgeschlossen. Befindet sich das
@
vor einer Öffnung (
, wird der gesamte Block in Klammern vom Phase-3-Echo ausgeschlossen.
- Prozessklammer (ermöglicht zusammengesetzte Anweisungen über mehrere Zeilen hinweg):
- Wenn der Parser nicht nach einem Befehlstoken sucht,
(
ist dies nichts Besonderes.
- Wenn der Parser nach einem Befehlstoken sucht und dieses findet
(
, starten Sie eine neue zusammengesetzte Anweisung und erhöhen Sie den Klammerzähler
- Wenn der Klammerzähler> 0 ist
)
, wird die zusammengesetzte Anweisung beendet und der Klammerzähler dekrementiert.
- Wenn das Zeilenende erreicht ist und der Klammerzähler> 0 ist, wird die nächste Zeile an die zusammengesetzte Anweisung angehängt (beginnt erneut mit Phase 0).
- Wenn der Klammerzähler 0 ist und der Parser nach einem Befehl sucht,
)
funktioniert er ähnlich wie eine REM
Anweisung, solange unmittelbar darauf ein Token-Trennzeichen, ein Sonderzeichen, eine neue Zeile oder ein Dateiende folgt
- Alle Sonderzeichen verlieren ihre Bedeutung außer
^
(Zeilenverkettung ist möglich)
- Sobald das Ende der logischen Zeile erreicht ist, wird der gesamte "Befehl" verworfen.
- Jeder Befehl wird in eine Reihe von Token analysiert. Das erste Token wird immer als Befehlstoken behandelt (nachdem das Special entfernt
@
und die Umleitung an das Ende verschoben wurde).
- Führende Token-Trennzeichen vor dem Befehlstoken werden entfernt
- Funktioniert beim Parsen des Befehlstokens
(
zusätzlich zu den Standard-Token-Trennzeichen als Befehlstoken-Begrenzer
- Die Behandlung nachfolgender Token hängt vom Befehl ab.
- Die meisten Befehle verketten einfach alle Argumente nach dem Befehlstoken zu einem einzigen Argumenttoken. Alle Trennzeichen für Argumenttoken bleiben erhalten. Argumentoptionen werden normalerweise erst in Phase 7 analysiert.
- Drei Befehle werden speziell behandelt - IF, FOR und REM
- IF ist in zwei oder drei verschiedene Teile aufgeteilt, die unabhängig voneinander verarbeitet werden. Ein Syntaxfehler in der IF-Konstruktion führt zu einem schwerwiegenden Syntaxfehler.
- Die Vergleichsoperation ist der eigentliche Befehl, der bis zur Phase 7 durchläuft
- Alle IF-Optionen werden in Phase 2 vollständig analysiert.
- Aufeinanderfolgende Token-Begrenzer werden in einem einzigen Leerzeichen zusammengefasst.
- Abhängig vom Vergleichsoperator werden ein oder zwei Wertmarken identifiziert.
- Der True-Befehlsblock ist der Befehlssatz nach der Bedingung und wird wie jeder andere Befehlsblock analysiert. Wenn ELSE verwendet werden soll, muss der True-Block in Klammern gesetzt werden.
- Der optionale Befehlsblock False ist der Befehlssatz nach ELSE. Auch dieser Befehlsblock wird normal analysiert.
- Die Befehlsblöcke True und False fließen nicht automatisch in die nachfolgenden Phasen. Ihre nachfolgende Verarbeitung wird durch Phase 7 gesteuert.
- FOR wird nach dem DO in zwei Teile geteilt. Ein Syntaxfehler in der FOR-Konstruktion führt zu einem schwerwiegenden Syntaxfehler.
- Der Teil durch DO ist der eigentliche FOR-Iterationsbefehl, der den gesamten Weg durch Phase 7 durchläuft
- Alle FOR-Optionen werden in Phase 2 vollständig analysiert.
- Die IN-Klausel in Klammern behandelt
<LF>
als <space>
. Nachdem die IN-Klausel analysiert wurde, werden alle Token zu einem einzigen Token zusammengefasst.
- Aufeinanderfolgende nicht begrenzte / nicht zitierte Token-Trennzeichen werden während des gesamten FOR-Befehls über DO in einem einzigen Leerzeichen zusammengefasst.
- Der Teil nach DO ist ein Befehlsblock, der normal analysiert wird. Die nachfolgende Verarbeitung des DO-Befehlsblocks wird durch die Iteration in Phase 7 gesteuert.
- In Phase 2 erkanntes REM wird dramatisch anders behandelt als alle anderen Befehle.
- Es wird nur ein Argument-Token analysiert - der Parser ignoriert Zeichen nach dem ersten Argument-Token.
- Der REM-Befehl wird möglicherweise in der Ausgabe der Phase 3 angezeigt, der Befehl wird jedoch nie ausgeführt, und der ursprüngliche Argumenttext wird wiederholt. Escape-Carets werden nicht entfernt, außer ...
- Wenn es nur ein Argument-Token gibt, das mit einem Leerzeichen
^
endet, das die Zeile beendet, wird das Argument-Token weggeworfen und die nachfolgende Zeile wird analysiert und an das REM angehängt. Dies wird wiederholt, bis mehr als ein Token vorhanden ist oder das letzte Zeichen nicht mehr vorhanden ist ^
.
- Wenn das Befehlstoken mit beginnt
:
und dies die erste Runde von Phase 2 ist (kein Neustart aufgrund von CALL in Phase 6), dann
- Das Token wird normalerweise als nicht ausgeführtes Label behandelt .
- Der Rest der Zeile wird analysiert, aber
)
, <
, >
, &
und |
nicht mehr hat eine besondere Bedeutung. Der gesamte Rest der Zeile wird als Teil der Bezeichnung "Befehl" betrachtet.
- Das ist
^
weiterhin etwas Besonderes, dh die Zeilenfortsetzung kann verwendet werden, um die nachfolgende Zeile an das Etikett anzuhängen.
- Ein nicht ausgeführtes Label in einem Block in Klammern führt zu einem schwerwiegenden Syntaxfehler, es sei denn, in der nächsten Zeile folgt sofort ein Befehl oder ein ausgeführtes Label .
(
hat keine besondere Bedeutung mehr für den ersten Befehl, der auf das nicht ausgeführte Label folgt .
- Der Befehl wird abgebrochen, nachdem die Etikettenanalyse abgeschlossen ist. Nachfolgende Phasen finden für das Etikett nicht statt
- Es gibt drei Ausnahmen, die dazu führen können, dass ein in Phase 2 gefundenes Label als ausgeführtes Label behandelt wird , das die Analyse in Phase 7 fortsetzt.
- Es ist die Umleitung , dass das Etikett vorangeht Token und es gibt ein
|
Rohr oder &
, &&
oder ||
Befehlsverkettung auf der Linie.
- Vor dem Label-Token steht eine Umleitung, und der Befehl befindet sich in einem Block in Klammern.
- Das Label-Token ist der allererste Befehl in einer Zeile innerhalb eines Blocks in Klammern, und die obige Zeile endete mit einem nicht ausgeführten Label .
- Folgendes tritt auf, wenn in Phase 2 ein ausgeführtes Label entdeckt wird
- Das Label, seine Argumente und seine Umleitung sind in Phase 3 von jeder Echoausgabe ausgeschlossen
- Alle nachfolgenden verketteten Befehle in der Zeile werden vollständig analysiert und ausgeführt.
- Weitere Informationen zu Ausgeführt Labels vs. Nicht ausgeführte Labels finden https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405
Phase 3) Echo der analysierten Befehle Nur dann, wenn der Befehlsblock nicht mit begonnen @
hat und ECHO zu Beginn des vorherigen Schritts eingeschaltet war.
Phase 4) FOR- %X
Variablenerweiterung: Nur wenn ein FOR-Befehl aktiv ist und die Befehle nach DO verarbeitet werden.
- Zu diesem Zeitpunkt hat Phase 1 der Stapelverarbeitung bereits eine FOR-Variable wie
%%X
in konvertiert %X
. Die Befehlszeile hat unterschiedliche prozentuale Erweiterungsregeln für Phase 1. Dies ist der Grund, warum Befehlszeilen %X
Batch-Dateien %%X
für FOR-Variablen verwenden.
- FOR-Variablennamen unterscheiden zwischen Groß- und Kleinschreibung, jedoch
~modifiers
nicht zwischen Groß- und Kleinschreibung.
~modifiers
Vorrang vor Variablennamen haben. Wenn ein nachfolgendes Zeichen ~
sowohl ein Modifikator als auch ein gültiger FOR-Variablenname ist und ein nachfolgendes Zeichen vorhanden ist, das ein aktiver FOR-Variablenname ist, wird das Zeichen als Modifikator interpretiert.
- FOR-Variablennamen sind global, jedoch nur im Kontext einer DO-Klausel. Wenn eine Routine aus einer FOR DO-Klausel heraus aufgerufen wird, werden die FOR-Variablen innerhalb der CALLed-Routine nicht erweitert. Wenn die Routine jedoch über einen eigenen FOR-Befehl verfügt, sind alle derzeit definierten FOR-Variablen für die inneren DO-Befehle zugänglich.
- FOR-Variablennamen können in verschachtelten FORs wiederverwendet werden. Der innere FOR-Wert hat Vorrang, aber sobald INNER FOR geschlossen wird, wird der äußere FOR-Wert wiederhergestellt.
- Wenn ECHO zu Beginn dieser Phase eingeschaltet war, wird Phase 3) wiederholt, um die analysierten DO-Befehle anzuzeigen, nachdem die FOR-Variablen erweitert wurden.
---- Ab diesem Zeitpunkt wird jeder in Phase 2 identifizierte Befehl separat verarbeitet.
---- Die Phasen 5 bis 7 werden für einen Befehl abgeschlossen, bevor mit dem nächsten fortgefahren wird.
Phase 5) Verzögerte Erweiterung: Nur wenn die verzögerte Erweiterung aktiviert ist, befindet sich der Befehl nicht in einem Klammerblock auf beiden Seiten einer Pipe , und der Befehl ist kein "nacktes" Batch-Skript (Skriptname ohne Klammern, CALL, Befehlsverkettung, oder Rohr).
- Jedes Token für einen Befehl wird unabhängig für eine verzögerte Erweiterung analysiert.
- Die meisten Befehle analysieren zwei oder mehr Token - das Befehlstoken, das Argumenttoken und jedes Umleitungszieltoken.
- Der FOR-Befehl analysiert nur das IN-Klauseltoken.
- Der IF-Befehl analysiert nur die Vergleichswerte - je nach Vergleichsoperator entweder einen oder zwei.
- Überprüfen Sie für jedes analysierte Token zunächst, ob es eines enthält
!
. Wenn nicht, wird das Token nicht analysiert - wichtig für ^
Zeichen. Wenn das Token enthält !
, scannen Sie jedes Zeichen von links nach rechts:
- Wenn es sich um ein Caret (
^
) handelt, hat das nächste Zeichen keine besondere Bedeutung, das Caret selbst wird entfernt
- Wenn es sich um ein Ausrufezeichen handelt, suchen Sie nach dem nächsten Ausrufezeichen (Carets werden nicht mehr beobachtet) und erweitern Sie es auf den Wert der Variablen.
- Aufeinanderfolgende Öffnungen
!
werden zu einer einzigen zusammengefasst!
- Verbleibende ungepaarte
!
werden entfernt
- Das Erweitern von vars in dieser Phase ist "sicher", da Sonderzeichen nicht mehr erkannt werden (gerade
<CR>
oder <LF>
)
- Für eine vollständigere Erklärung lesen Sie die 2. Hälfte davon aus dbenham
gleichen Thread - Ausrufezeichen Phase
Phase 5.3) Rohrverarbeitung: Nur wenn sich Befehle auf beiden Seiten eines Rohrs befinden
Jede Seite des Rohrs wird unabhängig und asynchron verarbeitet.
- Wenn der Befehl in cmd.exe intern ist oder es sich um eine Batchdatei handelt oder wenn es sich um einen Befehlsblock in Klammern handelt, wird er in einem neuen cmd.exe-Thread über ausgeführt
%comspec% /S /D /c" commandBlock"
, sodass der Befehlsblock einen Phasenneustart erhält, diesmal jedoch im Befehlszeilenmodus.
- Wenn ein Befehlsblock in Klammern steht, werden alle
<LF>
mit einem Befehl davor und danach in konvertiert <space>&
. Andere <LF>
werden abgestreift.
- Dies ist das Ende der Verarbeitung für die Pipe-Befehle.
- Siehe Warum schlägt die verzögerte Erweiterung fehl, wenn sie sich in einem Pipeline-Codeblock befindet? Weitere Informationen zum Parsen und Verarbeiten von Rohren
Phase 5.5) Umleitung ausführen: Jede in Phase 2 erkannte Umleitung wird jetzt ausgeführt.
Phase 6) CALL-Verarbeitung / Caret-Verdopplung: Nur wenn das Befehlstoken CALL ist oder wenn der Text vor dem ersten vorkommenden Standard-Token-Trennzeichen CALL ist. Wenn CALL von einem größeren Befehlstoken analysiert wird, wird der nicht verwendete Teil dem Argumenttoken vorangestellt, bevor Sie fortfahren.
- Scannen Sie das Argument-Token nach einem nicht zitierten
/?
. Wenn sich irgendwo innerhalb der Token etwas befindet, brechen Sie Phase 6 ab und fahren Sie mit Phase 7 fort, in der die HILFE für ANRUF gedruckt wird.
- Entfernen Sie den ersten
CALL
, damit mehrere CALLs gestapelt werden können
- Verdoppeln Sie alle Carets
- Starten Sie die Phasen 1, 1.5 und 2 neu, fahren Sie jedoch nicht mit Phase 3 fort
- Doppelte Carets werden auf ein Caret reduziert, solange sie nicht zitiert werden. Leider bleiben die zitierten Carets verdoppelt.
- Phase 1 ändert sich etwas
- Erweiterungsfehler in Schritt 1.2 oder 1.3 brechen den CALL ab, aber der Fehler ist nicht schwerwiegend - die Stapelverarbeitung wird fortgesetzt.
- Phase-2-Aufgaben werden etwas geändert
- Jede neu auftretende nicht zitierte, nicht entführte Umleitung, die in der ersten Runde von Phase 2 nicht erkannt wurde, wird erkannt, aber entfernt (einschließlich des Dateinamens), ohne die Umleitung tatsächlich durchzuführen
- Jedes neu erscheinende nicht zitierte, nicht entflohene Caret am Ende der Zeile wird entfernt, ohne dass eine Fortsetzung der Zeile durchgeführt wird
- Der CALL wird ohne Fehler abgebrochen, wenn einer der folgenden Fehler erkannt wird
- Neu erscheinend ohne Zitat, ohne Flucht
&
oder|
- Das resultierende Befehlstoken beginnt mit nicht zitiert, nicht entführt
(
- Der allererste Token nach dem entfernten CALL begann mit
@
- Wenn der resultierende Befehl ein scheinbar gültiges IF oder FOR ist, schlägt die Ausführung anschließend mit einem Fehler fehl, der angibt, dass er als interner oder externer Befehl erkannt wird
IF
oder FOR
nicht.
- Natürlich wird der CALL in dieser zweiten Runde von Phase 2 nicht abgebrochen, wenn das resultierende Befehlstoken eine Bezeichnung ist, die mit beginnt
:
.
- Wenn das resultierende Befehlstoken CALL ist, starten Sie Phase 6 neu (wiederholt sich, bis kein CALL mehr erfolgt).
- Wenn das resultierende Befehlstoken ein Batch-Skript oder ein: -Label ist, wird die Ausführung des CALL im Rest von Phase 6 vollständig ausgeführt.
- Verschieben Sie die aktuelle Position der Batch-Skriptdatei auf den Aufrufstapel, damit die Ausführung an der richtigen Position fortgesetzt werden kann, wenn der Aufruf abgeschlossen ist.
- Richten Sie die Argumenttoken% 0,% 1,% 2, ...% N und% * für den CALL unter Verwendung aller resultierenden Token ein
- Wenn das Befehlstoken eine Bezeichnung ist, die mit beginnt
:
, dann
- Starten Sie Phase 5 neu. Dies kann sich auf Folgendes auswirken: Label wird aufgerufen. Da die Token% 0 usw. bereits eingerichtet wurden, werden die Argumente, die an die Routine CALLed übergeben werden, nicht geändert.
- Führen Sie das GOTO-Label aus, um den Dateizeiger am Anfang des Unterprogramms zu positionieren (ignorieren Sie alle anderen Token, die möglicherweise dem: label folgen). In Phase 7 finden Sie Regeln zur Funktionsweise von GOTO.
- Wenn das Token: label fehlt oder das Label: nicht gefunden wird, wird der Aufrufstapel sofort geöffnet, um die gespeicherte Dateiposition wiederherzustellen, und der CALL wird abgebrochen.
- Wenn das: -Label /? Enthält, wird die GOTO-Hilfe gedruckt, anstatt nach dem: -Label zu suchen. Der Dateizeiger bewegt sich nicht, sodass der Code nach dem CALL zweimal ausgeführt wird, einmal im CALL-Kontext und dann erneut nach der CALL-Rückkehr. Siehe Warum CALL die GOTO-Hilfemeldung in diesem Skript druckt. Und warum werden Befehle danach zweimal ausgeführt? Für mehr Information.
- Andernfalls wird die Steuerung an das angegebene Batch-Skript übertragen.
- Die Ausführung des CALLed: -Labels oder -Skripts wird fortgesetzt, bis entweder EXIT / B oder das Dateiende erreicht ist. An diesem Punkt wird der CALL-Stapel gelöscht und die Ausführung an der gespeicherten Dateiposition fortgesetzt.
Phase 7 wird nicht für aufgerufene Skripte oder: Labels ausgeführt.
- Andernfalls fällt das Ergebnis von Phase 6 zur Ausführung in Phase 7 durch.
Phase 7) Ausführen: Der Befehl wird ausgeführt
- 7.1 - Internen Befehl ausführen - Wenn das Befehlstoken in Anführungszeichen gesetzt ist, überspringen Sie diesen Schritt. Versuchen Sie andernfalls, einen internen Befehl zu analysieren und auszuführen.
- Die folgenden Tests werden durchgeführt, um festzustellen, ob ein nicht zitiertes Befehlstoken einen internen Befehl darstellt:
- Wenn das Befehlstoken genau mit einem internen Befehl übereinstimmt, führen Sie ihn aus.
- Andernfalls brechen Sie das Befehlstoken vor dem ersten Auftreten von
+
/
[
]
<space>
<tab>
,
;
oder. =
Wenn der vorhergehende Text ein interner Befehl ist, merken Sie sich diesen Befehl
- Wenn Sie sich im Befehlszeilenmodus befinden oder wenn der Befehl aus einem Block in Klammern stammt, wenn der Befehlsblock true oder false, der Befehlsblock FOR DO oder an der Befehlsverkettung beteiligt ist, führen Sie den internen Befehl aus
- Andernfalls (muss im Batch-Modus ein eigenständiger Befehl sein) durchsuchen Sie den aktuellen Ordner und den PATH nach einer .COM-, .EXE-, .BAT- oder .CMD-Datei, deren Basisname mit dem ursprünglichen Befehlstoken übereinstimmt
- Wenn die erste übereinstimmende Datei eine .BAT- oder .CMD-Datei ist, gehen Sie zu 7.3.exec und führen Sie das Skript aus
- Andernfalls (Übereinstimmung nicht gefunden oder erste Übereinstimmung ist .EXE oder .COM) führen Sie den gespeicherten internen Befehl aus
- Andernfalls brechen Sie das Befehlstoken vor dem ersten Auftreten von
.
\
oder. :
Wenn der vorhergehende Text kein interner Befehl ist, gehen Sie zu 7.2.
Andernfalls kann der vorhergehende Text ein interner Befehl sein. Denken Sie an diesen Befehl.
- Unterbrechen Sie das Befehlstoken vor dem ersten Auftreten von
+
/
[
]
<space>
<tab>
,
;
oder. =
Wenn der vorhergehende Text ein Pfad zu einer vorhandenen Datei ist, gehen Sie zu 7.2.
Andernfalls führen Sie den gespeicherten internen Befehl aus.
- Wenn ein interner Befehl von einem größeren Befehlstoken analysiert wird, wird der nicht verwendete Teil des Befehlstokens in die Argumentliste aufgenommen
- Nur weil ein Befehlstoken als interner Befehl analysiert wird, bedeutet dies nicht, dass er erfolgreich ausgeführt wird. Jeder interne Befehl hat seine eigenen Regeln, wie die Argumente und Optionen analysiert werden und welche Syntax zulässig ist.
- Alle internen Befehle drucken die Hilfe, anstatt ihre Funktion auszuführen, wenn sie
/?
erkannt werden. Die meisten erkennen, /?
ob es irgendwo in den Argumenten erscheint. Einige Befehle wie ECHO und SET drucken jedoch nur dann Hilfe, wenn das erste Argument-Token mit beginnt /?
.
- SET hat einige interessante Semantik:
- Wenn ein SET-Befehl ein Anführungszeichen enthält, bevor der Variablenname und die Erweiterungen aktiviert sind
set "name=content" ignored
-> value =, content
wird der Text zwischen dem ersten Gleichheitszeichen und dem letzten Anführungszeichen als Inhalt verwendet (erstes Gleichheitszeichen und letztes Anführungszeichen ausgeschlossen). Text nach dem letzten Anführungszeichen wird ignoriert. Wenn nach dem Gleichheitszeichen kein Anführungszeichen steht, wird der Rest der Zeile als Inhalt verwendet.
- Wenn ein SET-Befehl kein Anführungszeichen vor dem Namen
set name="content" not ignored
-> value = enthält, "content" not ignored
wird der gesamte Rest der Zeile nach dem Gleichwert als Inhalt verwendet, einschließlich aller möglicherweise vorhandenen Anführungszeichen.
- Ein IF-Vergleich wird ausgewertet, und abhängig davon, ob die Bedingung wahr oder falsch ist, wird der entsprechende bereits analysierte abhängige Befehlsblock ab Phase 5 verarbeitet.
- Die IN-Klausel eines FOR-Befehls wird entsprechend iteriert.
- Wenn dies ein FOR / F ist, das die Ausgabe eines Befehlsblocks wiederholt, dann:
- Die IN-Klausel wird in einem neuen cmd.exe-Prozess über CMD / C ausgeführt.
- Der Befehlsblock muss den gesamten Analyseprozess ein zweites Mal durchlaufen, diesmal jedoch in einem Befehlszeilenkontext
- ECHO startet EIN und die verzögerte Erweiterung wird normalerweise deaktiviert gestartet (abhängig von der Registrierungseinstellung).
- Alle vom Befehlsblock der IN-Klausel vorgenommenen Umgebungsänderungen gehen verloren, sobald der untergeordnete Prozess cmd.exe beendet wird
- Für jede Iteration:
- Die FOR-Variablenwerte sind definiert
- Der bereits analysierte DO-Befehlsblock wird dann ab Phase 4 verarbeitet.
- GOTO verwendet die folgende Logik, um das Label zu finden
- Das Label wird vom ersten Argument-Token analysiert
- Das Skript wird nach dem nächsten Auftreten des Etiketts durchsucht
- Der Scan beginnt an der aktuellen Dateiposition
- Wenn das Dateiende erreicht ist, kehrt der Scan zum Anfang der Datei zurück und fährt mit dem ursprünglichen Startpunkt fort.
- Der Scan wird beim ersten Auftreten des gefundenen Etiketts gestoppt, und der Dateizeiger wird auf die Zeile unmittelbar nach dem Etikett gesetzt. Die Ausführung des Skripts wird ab diesem Zeitpunkt fortgesetzt. Beachten Sie, dass ein erfolgreiches echtes GOTO jeden analysierten Codeblock, einschließlich FOR-Schleifen, sofort abbricht.
- Wenn das Etikett nicht gefunden wird oder das Etikettentoken fehlt, schlägt das GOTO fehl, eine Fehlermeldung wird gedruckt und der Aufrufstapel wird gelöscht. Dies funktioniert effektiv als EXIT / B, außer dass bereits analysierte Befehle im aktuellen Befehlsblock, die auf GOTO folgen, noch ausgeführt werden, jedoch im Kontext des CALLer (dem Kontext, der nach EXIT / B existiert).
- Unter https://www.dostips.com/forum/viewtopic.php?f=3&t=3803 finden Sie eine genauere Beschreibung der Regeln, die zum Parsen von Labels verwendet werden.
- RENAME und COPY akzeptieren Platzhalter für den Quell- und den Zielpfad. Aber Microsoft macht einen schrecklichen Job und dokumentiert, wie die Platzhalter funktionieren, insbesondere für den Zielpfad. Eine nützliche Reihe von Platzhalterregeln finden Sie unter Wie interpretiert der Windows-Befehl RENAME Platzhalter?
- 7.2 - Volumenänderung ausführen - Wenn das Befehlstoken nicht mit einem Anführungszeichen beginnt, genau zwei Zeichen lang ist und das zweite Zeichen ein Doppelpunkt ist, ändern Sie die Lautstärke
- Alle Argumenttoken werden ignoriert
- Wenn das durch das erste Zeichen angegebene Volume nicht gefunden werden kann, brechen Sie den Vorgang mit einem Fehler ab
- Ein Befehlstoken von
::
führt immer zu einem Fehler, es sei denn, SUBST wird zum Definieren eines Volumes für verwendet. ::
Wenn SUBST zum Definieren eines Volumes für verwendet wird ::
, wird das Volume geändert und nicht als Bezeichnung behandelt.
- 7.3 - Externen Befehl ausführen - Andernfalls versuchen Sie, den Befehl als externen Befehl zu behandeln.
- Wenn im Befehlszeilenmodus und der Befehl nicht zitiert wird , und beginnt nicht mit einem Volumen Spezifikation, white-space,
,
, ;
, =
oder +
dann den Befehl beim ersten Auftreten Token brechen von <space>
,
;
oder =
und stellen Sie vor dem Rest das Argument Token (s).
- Wenn das 2. Zeichen des Befehlstokens ein Doppelpunkt ist, überprüfen Sie, ob das durch das 1. Zeichen angegebene Volume gefunden werden kann.
Wenn das Volume nicht gefunden werden kann, brechen Sie den Vorgang mit einem Fehler ab.
- Wenn im Batch-Modus das Befehlstoken mit beginnt
:
, gehen Sie zu 7.4.
Beachten Sie, dass wenn das Label-Token mit beginnt ::
, dies nicht erreicht wird, da der vorherige Schritt mit einem Fehler abgebrochen wurde, es sei denn, SUBST wird zum Definieren eines Volumes für verwendet ::
.
- Identifizieren Sie den auszuführenden externen Befehl.
- Dies ist ein komplexer Prozess, der das aktuelle Volume, das aktuelle Verzeichnis, die PATH-Variable, die PATHEXT-Variable und / oder Dateizuordnungen umfassen kann.
- Wenn ein gültiger externer Befehl nicht identifiziert werden kann, brechen Sie den Vorgang mit einem Fehler ab.
- Wenn im Befehlszeilenmodus und das Befehlstoken mit beginnt
:
, gehen Sie zu 7.4.
Beachten Sie, dass dies selten erreicht wird, da der vorherige Schritt mit einem Fehler abgebrochen wurde, es sei denn, das Befehlstoken beginnt mit ::
und SUBST wird verwendet, um ein Volume für ::
und zu definieren Das gesamte Befehlstoken ist ein gültiger Pfad zu einem externen Befehl.
- 7.3.exec - Führen Sie den externen Befehl aus.
- 7.4 - Beschriftung ignorieren - Ignoriert den Befehl und alle seine Argumente, wenn das Befehlstoken mit beginnt
:
.
Die Regeln in 7.2 und 7.3 können verhindern, dass ein Etikett diesen Punkt erreicht.
Befehlszeilen-Parser:
Funktioniert wie der BatchLine-Parser, außer:
Phase 1) Prozentuale Expansion:
- Nein
%*
, %1
usw. Argument Expansion
- Wenn var undefiniert
%var%
ist, bleibt es unverändert.
- Keine besondere Behandlung von
%%
. Wenn var = content, wird auf %%var%%
erweitert %content%
.
Phase 3) Geben Sie die analysierten Befehle wieder.
- Dies wird nicht nach Phase 2 durchgeführt. Es wird nur nach Phase 4 für den FOR DO-Befehlsblock durchgeführt.
Phase 5) Verzögerte Erweiterung: Nur wenn DelayedExpansion aktiviert ist
- Wenn var undefiniert
!var!
ist, bleibt es unverändert.
Phase 7) Befehl ausführen
- Versuche, a: label anzurufen oder zu erhalten, führen zu einem Fehler.
- Wie bereits in Phase 7 dokumentiert, kann ein ausgeführtes Label in verschiedenen Szenarien zu einem Fehler führen.
- Stapelausgeführte Etiketten können nur dann einen Fehler verursachen, wenn sie mit beginnen
::
- Über die Befehlszeile ausgeführte Beschriftungen führen fast immer zu einem Fehler
Parsen von Ganzzahlwerten
Es gibt viele verschiedene Kontexte, in denen cmd.exe ganzzahlige Werte aus Zeichenfolgen analysiert und die Regeln inkonsistent sind:
SET /A
IF
%var:~n,m%
(variable Teilstring-Erweiterung)
FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Details zu diesen Regeln finden Sie unter Regeln, wie CMD.EXE Zahlen analysiert
Für alle, die die Parsing-Regeln für cmd.exe verbessern möchten, gibt es im DosTips-Forum ein Diskussionsthema, in dem Probleme gemeldet und Vorschläge gemacht werden können.
Hoffe es hilft
Jan Erik (jeb) - Ursprünglicher Autor und Entdecker der Phasen
Dave Benham (dbenham) - Viel zusätzlicher Inhalt und Bearbeitung