Frage

Ich lief in ss64.com die gute Hilfe bietet darüber, wie Batch-Skripten zu schreiben, dass der Windows-Befehlsinterpreter wird Lauf.

Allerdings habe ich es nicht gelungen, eine gute Erklärung für die Grammatik finden von Batch-Skripten, wie die Dinge zu erweitern oder erweitern nicht, und wie die Dinge zu entkommen.

Hier sind Beispiele von Fragen, dass ich nicht in der Lage zu lösen:

  • Wie wird das Angebotssystem verwaltet? Ich habe einen TinyPerl Skript
    (foreach $i (@ARGV) { print '*' . $i ; }), kompiliert es und es auf diese Weise genannt:
    • my_script.exe "a ""b"" c" ? Ausgang ist *a "b*c
    • my_script.exe """a b c""" ? Ausgang es *"a*b*c"
  • Wie funktioniert die interne echo Befehl Arbeit? Was innerhalb dieses Befehls erweitert wird?
  • Warum habe ich for [...] %%I in Datei-Skripte verwenden, aber for [...] %I in interaktiven Sitzungen?
  • Was sind die Escape-Zeichen, und in welchem ??Kontext? Wie ein Prozentzeichen zu entkommen? Zum Beispiel: Wie kann ich echo %PROCESSOR_ARCHITECTURE% wahrsten Sinn des Wortes? Ich, dass echo.exe %""PROCESSOR_ARCHITECTURE% Werke gefunden, gibt es eine bessere Lösung?
  • Wie Paare von % Spiel? Beispiel:
    • set b=a, echo %a %b% c% ? %a a c%
    • set a =b, echo %a %b% c% ? bb c%
  • Wie stelle ich sicher eine Variable geht auf einen Befehl als ein einziges Argument, wenn überhaupt diese Variable doppelte Anführungszeichen enthält?
  • Wie werden die gespeicherten Variablen bei der set Befehl? Zum Beispiel, wenn ich set a=a" b tun und dann echo.%a% erhalte ich a" b. Wenn ich aber echo.exe von den UnxUtils verwenden, erhalte ich a b. Wie kommt %a% dehnt sich auf eine andere Weise?

Vielen Dank für Ihre Beleuchtung.

War es hilfreich?

Lösung

Wir führten Experimente, die Grammatik von Batch-Skripten zu untersuchen. Wir auch Unterschiede zwischen Batch- und Kommandozeilen-Modus untersucht.

Batch-Linie Parser:

Hier ist ein kurzer Überblick über die bei der Verarbeitung eine Codezeile beteiligten Phasen in einer Batch-Datei:

Phase 0) Read Line:

Phase 1) Prozent Expansion:

Phase 1.5) Remove <CR>: Entfernen Sie alle Carriage Return (0x0D) Zeichen

Phase 2) Prozesssonderzeichen, tokenize und baut einen im Cache gespeicherte Befehlsblock: Dies ist ein komplexer Prozess, der durch Dinge wie Angebote, Sonderzeichen, Token-Trennzeichen betroffen ist, und caret entkommen.

Phase 3) Echo des geparsten Befehl (e) Nur wenn der Befehlsblock mit @ nicht beginnen, und ECHO war zu Beginn des vorhergehenden Schritts ON.

Phase 4) FÜR %X variable Erweiterung:. Nur wenn ein Befehl FOR aktiv ist und die Befehle nach DO verarbeitet werden

Phase 5) Verzögerte Expansion: Nur wenn verzögerte Expansion aktiviert

Phase 5.3) Rohrbearbeitung: Nur wenn Befehle auf beiden Seiten eines Rohres sind

Phase 5.5) ausführen Redirection:

Phase 6) CALL-Verarbeitung / Caret Verdoppelung: Nur wenn der Befehl Token CALL-

Phase 7) ausführen: Der Befehl ausgeführt wird


Hier sind Details für jede Phase:

Beachten Sie, dass die Phasen im Folgenden beschrieben sind nur ein Beispiel dafür, wie die Chargen Parser funktioniert. Die tatsächlichen cmd.exe Einbauten können reflektieren nicht diese Phasen. Aber dieses Modell ist wirksam bei Verhalten von Batch-Skripten der Vorhersage.

Phase 0) Read Line:. Lesen Eingabezeile durch die erste <LF>

  • Wenn eine Zeile zu lesen als Befehl analysiert werden, <Ctrl-Z> (0x1A) gelesen als <LF> (Zeilenvor 0x0A)
  • Wenn GOTO oder Ruflinien liest während des Scannens für ein: label, <Ctrl-Z>, als selbst behandelt - es ist nicht umgewandelt <LF>

Phase 1) Prozent Expansion:

  • Ein Doppel %% durch einen einzigen % ersetzt
  • Ausbau der Argumente (%*, %1, %2 usw.)
  • Ausbau der %var%, wenn var existiert es nicht ersetzen mit nichts
  • Line abgeschnitten zunächst <LF> nicht innerhalb %var% Erweiterung
  • für eine vollständige Erklärung lesen Sie die erste Hälfte aus dbenham selben Thread: Prozent Phase

Phase 1.5) Remove <CR>: Entfernen all Carriage Returns (0x0D) von der Linie

Phase 2) Prozesssonderzeichen, tokenize und baut einen im Cache gespeicherte Befehlsblock: Dies ist ein komplexer Prozess, der durch Dinge wie Angebote, Sonderzeichen, Token-Trennzeichen betroffen ist, und caret entkommen. Was folgt, ist eine Annäherung an diesem Prozess.

Es gibt Konzepte, die in dieser Phase wichtig sind.

  • Ein Token ist einfach eine Folge von Zeichen, die als Einheit behandelt wird.
  • Tokens werden von Token-Trennzeichen getrennt. Die Standard-Token-Trennzeichen sind <space> <tab> ; , = <0x0B> <0x0C> und <0xFF>
    Aufeinander folgende Token-Trennzeichen werden behandelt, als ein - es gibt keine leeren Token zwischen Token-Trennzeichen
  • Es sind keine Token-Trennzeichen in einer Zeichenfolge in Anführungszeichen. Die gesamte Zeichenfolge in Anführungszeichen wird immer als Teil eines einzigen Token behandelt. Ein einzelne Zeichen aus einer Kombination von Strings in Anführungszeichen und nicht notierten Zeichen bestehen.

Die folgenden Zeichen können in dieser Phase besondere Bedeutung haben, je nach Kontext: ^ ( @ & | < > <LF> <space> <tab> ; , = <0x0B> <0x0C> <0xFF>

Schauen Sie sich jedes Zeichen von links nach rechts:

  • Wenn es ein Caret (^), wird das nächste Zeichen entkommen, und das entweichende caret entfernt wird. Maskierte Zeichen verlieren alle eine besondere Bedeutung (außer <LF>).
  • Wenn es sich um ein Zitat ("), Toggle das Zitat Flagge. Wenn das Zitat Flag aktiv ist, dann nur " und <LF> sind etwas Besonderes. Alle anderen Zeichen verlieren ihre besondere Bedeutung, bis das nächste Zitat das Zitat-Flag aus schaltet. Es ist nicht möglich, den Schlusskurs zu entkommen. Alle genannten Figuren sind immer in dem gleichen Grund.
  • <LF> dreht sich immer aus dem Zitat Flagge. Andere Verhaltensweisen variieren je nach Kontext, sondern zitiert nie das Verhalten von <LF> verändern.
    • Entkommen <LF>
      • <LF> abgestreift
      • Das nächste Zeichen ist entkommen. Wenn am Ende des Zeilenpuffers ist, dann wird die nächste Zeile gelesen und verarbeitet durch die Phasen 1 und 1,5 und die aktuellen beigefügte bevor das nächste Zeichen zu entkommen. Wenn das nächste Zeichen <LF> ist, dann wird es als Literal behandelt, diesen Prozess bedeutet nicht rekursiv ist.
    • Unescaped <LF> nicht in Klammern
      • <LF> wird abgezogen und das Parsen der aktuellen Zeile beendet ist.
      • Alle verbleibenden Zeichen in dem Zeilenpuffer einfach ignoriert werden.
    • Unescaped <LF> innerhalb eines IN klammerten Block
      • <LF> in eine <space>
      • umgewandelt
      • Wenn am Ende des Zeilenpuffers, dann die nächste Zeile gelesen wird und zu dem aktuellen angefügt.
    • Unescaped <LF> innerhalb eines geklammerten Befehlsblock
      • <LF> in <LF><space> umgewandelt, und das <space> wird als Teil der nächsten Zeile des Befehlsblocks behandelt.
      • Wenn am Ende des Zeilenpuffers, dann die nächste Zeile gelesen wird und zu dem Raum angehängt.
  • , wenn er eines der Sonderzeichen & | < oder > ist, aufgeteilt, um die Leitung an dieser Stelle, um Griffrohre, Befehlsverkettung und Umleitung.
    • Im Fall eines Rohres (|), ist jede Seite ein separater Befehl (oder Befehlsblock), die in Phase 5.3 spezielle Handhabung erhält
    • Im Fall von &, && oder || Befehlsverkettung, wobei jede Seite des Verkettungs als separaten Befehl behandelt wird.
    • Im Fall von <, <<, > oder >> Umleitung wird die Umleitung Klausel analysiert, vorübergehend entfernt und dann bis zum Ende des aktuellen Befehls angehängt. Eine Umleitung Klausel besteht aus einer optionalen Datei-Handle Ziffer, die Umleitungsoperator, und die Umleitung Ziel-Token.
      • Wenn das Token, dass geht der Umleitungsoperator eine einzelne Ziffer, dann die Ziffer bezeichnet die Datei-Handle zu umgeleitet werden. Wenn der Griff Token nicht gefunden wird, dann die Umleitung der Ausgabe standardmäßig auf 1 (stdout) und Eingabeumleitung automatisch auf 0 (stdin).
  • Wenn der erste für diesen Befehl Token (Stand der Umleitung zum Ende zu bewegen) beginnt mit @, dann hat die @ besondere Bedeutung. (@ ist in jedem anderen Kontext nicht speziell)
    • Die spezielle @ entfernt wird.
    • Falls ECHO ON ist, dann dieser Befehl zusammen mit irgendwelchen folgenden verketteten Befehlen auf dieser Linie ist aus der Phase 3 ausgeschlossen Echo. Wenn die @ vor einer Öffnung ( ist, dann wird der gesamte geklammerten Block von der Phase ausgeschlossen 3 Echo.
  • Prozess Klammer (sorgt für zusammengesetzte Anweisungen über mehrere Zeilen):
    • Wenn der Parser nicht für einen Befehl Token sucht, dann ( ist nicht besonders.
    • Wenn der Parser für einen Befehl Token und Funde ( sucht, dann eine neue Verbindung Anweisung starten und die Klammer Zählerinkrement
    • Wenn die Klammer Zähler> 0 dann ) beendet die Verbindung Anweisung und dekrementiert den Klammern Zähler.
    • Wenn das Zeilenende erreicht ist und die Klammer-Zähler> 0, dann wird die nächste Zeile wird zu der zusammengesetzten Anweisung angehängt wird (beginnt wieder mit Phase 0)
    • Wenn die Klammer Zähler 0 und der Parser für einen Befehl sucht, dann ) Funktionen ähnlich eine REM Anweisung, solange es sofort durch ein Token-Trennzeichen, Sonderzeichen folgt, Newline oder End-of-Datei
      • Alle Sonderzeichen verlieren ihre Bedeutung, außer ^ (line Verkettung möglich)
      • Sobald das Ende der logischen Zeile erreicht ist, wird der gesamte „Befehl“ verworfen.
  • Jeder Befehl wird in eine Reihe von Token analysiert. Der erste Token wird immer als ein Befehl behandelt Token (nach Sonder @ sind am Ende bewegt gestrippt und Umleitung wurde).
    • Führende Token-Trennzeichen vor dem Befehl Token abgezogen werden
    • Beim Lesen der Kommando Token, ( Funktionen als Befehl Token-Trennzeichen, zusätzlich zu den Standard-Token-Trennzeichen
    • Der Umgang mit nachfolgenden Token hängt von dem Befehl.
  • Die meisten Befehle einfach alle Argumente, die nach dem in einem einzigen Argument Token Token Befehl verketten. Alle Argument-Token-Trennzeichen werden beibehalten. Argument Optionen werden in der Regel nicht analysiert, bis Phase 7.
  • Drei Befehle erhalten spezielle Handhabung - IF, FOR, und REM
    • IF ist aufgeteilt in zwei oder drei verschiedene Teile, die unabhängig voneinander verarbeitet werden. Ein Syntaxfehler in der IF-Konstruktion wird in einem fatalen Syntaxfehler zur Folge hat.
      • Die Vergleichsoperation ist der eigentliche Befehl, der den ganzen Weg bis 7, um Phasenströmungen
        • Alle IF-Optionen werden in Phase 2 vollständig analysiert.
        • konsekutiv Token-Trennzeichen Zusammenbruch in einem einzigen Raum.
        • Je nach Vergleichsoperator, wird es eine oder zwei Wertmarken, die identifiziert werden.
      • Der wahre Befehlsblock ist der Satz von Befehlen nach dem Zustand und wird wie jeder anderer Befehlsblock analysiert. Wenn ELSE verwendet werden soll, dann muss der wahre Block klammerten werden.
      • Der optionale Falsche Befehlsblock ist der Satz von Befehlen nach ELSE. Auch dieser Befehlsblock normalerweise analysiert.
      • Die Wahr und Falsch Befehlsblöcke fließen nicht automatisch in den nachfolgenden Phasen. Deren anschließende Verarbeitung wird gesteuert durch Phase 7.
    • FOR wird in zwei nach dem DO aufgeteilt. Ein Syntaxfehler in der für die Konstruktion wird in einem fatalen Syntaxfehler führen.
      • Der Teil durch DO ist die eigentliche FOR Iteration Befehl, der den ganzen Weg durch Phasenströmungen 7
        • FOR Wahl Alle vollständig analysiert werden in Phase 2.
        • Die IN klammerten Klausel behandelt <LF> als <space>. Nachdem die IN-Klausel analysiert wird, werden alle Token verketteten zusammen ein einziges Token zu bilden.
        • konsekutiv unescaped / unquoted Token-Trennzeichen Zusammenbruch in einen einzigen Raum im ganzen der FOR-Befehl durch DO.
      • Der Teil nach DO ist ein Befehlsblock, der normalerweise analysiert wird. Weiterverarbeitung derDO Befehlsblock durch die Iteration in Phase 7 gesteuert wird.
    • REM erfasst in der Phase 2 als alle anderen Befehle dramatisch anders behandelt wird.
      • Nur ein Argument Token analysiert wird -. Der Parser Zeichen nach dem ersten Argument Token ignoriert
      • Der Befehl REM in Phase 3 Ausgabe erscheinen, aber der Befehl wird nie ausgeführt, und das ursprüngliche Argument Text anklingt - Flucht Carets nicht entfernt werden, es sei denn ...
        • Wenn es nur ein Argument-Token, das Enden mit einem unescaped ^ dass Enden der Leitung, dann das Argument Token weggeworfen wird, und die darauf folgende Zeile wird analysiert und mit dem REM angehängt. Dies wiederholt sich, bis es mehr als ein Token oder das letzte Zeichen nicht ^.
  • Wenn der Befehl Token mit : beginnt, und dies ist die erste Runde der Phase 2 (kein Neustart aufgrund CALL-in Phase 6) dann
    • Das Token normalerweise als ein behandelt wird Nicht ausgeführte Aufkleber .
      • Der Rest der Zeile analysiert wird, wird jedoch ), <, >, & und | nicht mehr haben besondere Bedeutung. Der gesamte Rest der Zeile wird als Teil des Labels „Befehl“ sein.
      • Die ^ weiterhin etwas Besonderes sein, dass Linienfortsetzungs Sinn verwendet werden, um die nachfolgende Zeile auf dem Etikett anzuhängen.
      • Ein Nicht ausgeführte Label- in einem geklammerten Block in einem fatalen Syntaxfehler führen wird, wenn es sofort durch einen Befehl oder Ausgeführt Aufkleber auf der nächsten Zeile folgt.
        • ( nicht mehr eine besondere Bedeutung für den ersten Befehl, der den Nicht ausgeführte Etikett folgt .
      • Der Befehl nach Label Parsing abgebrochen ist abgeschlossen. Nachfolgende Phasen finden nicht statt für das Label
    • Es gibt drei Ausnahmen, die ein Etikett in Phase gefunden verursachen können 2 als behandelt zu werden Ausgeführt Aufkleber , die durch Phase 7 weiter Parsen.
      • Es ist Umleitung, dass das Etikett vorangeht Token, und es gibt ein | Rohr oder &, && oder || Befehlsverkettung auf der Linie.
      • Es ist die Umleitung, dass geht die Label-Token und der Befehl ist in einem geklammerten Block.
      • Das Label Token ist der erste Befehl auf einer Linie innerhalb eines geklammerten Block, und die Linie oben endete mit einem Nicht ausgeführte Label-.
    • Die folgenden Ereignisse eintritt, wenn ein Ausgeführt Aufkleber in Phase entdeckt wird 2
      • Das Etikett, die Argumente und ihre Weiterleitung sind alle aus jedem Echoausgang in Phase ausgeschlossen 3
      • Alle nachfolgenden verketteten Befehle auf der Linie vollständig analysiert und ausgeführt.
    • Für weitere Informationen über Ausgeführt Labels vs. Nicht ausgeführte Labels finden Sie unter https://www.dostips.com/forum/viewtopic.php?f=3&t=3803&p=55405#p55405

Phase 3) Echo des geparsten Befehl (e) Nur wenn der Befehlsblock mit @ nicht beginnen, und ECHO war zu Beginn des vorhergehenden Schritts ON.

Phase 4) FÜR %X variable Erweiterung:. Nur wenn ein Befehl FOR aktiv ist und die Befehle nach DO verarbeitet werden

  • An diesem Punkt der Phase 1 der Stapelverarbeitung wird bereits eine für die Variable wie %%X in %X umgewandelt. Die Befehlszeile verschiedene Prozent Erweiterungsregeln für Phase 1. Dies ist der Grund dafür ist, dass Befehlszeilen verwenden %X aber Batch-Dateien %%X verwenden für für Variablen.
  • für Variablennamen sind Groß- und Kleinschreibung, aber ~modifiers sind nicht Groß- und Kleinschreibung.
  • ~modifiers hat Vorrang vor Variablennamen. Wenn ein Zeichen nach ~ beide ist ein Modifikator und eine gültige für Variablennamen, und es existiert ein nachfolgendes Zeichen, das eine aktive FOR Variablenname ist, dann wird das Zeichen als Modifikator interpretiert.
  • für Variablennamen sind global, sondern nur im Rahmen einer Klausel DO. Wenn eine Routine innerhalb einer DO-Klausel genannt wird, dann werden die für Variablen innerhalb der aufgerufenen Routine nicht erweitert. Aber wenn die Routine seinen eigenen FOR-Befehl hat, dann alle zur Zeit für Variablen definiert sind zugänglich für die inneren DO-Befehle.
  • für Variablennamen können in verschachtelten Fors wiederverwendet werden. Der innere FOR Wert hat Vorrang, aber sobald die INNER FOR schließt, dann wird der äußere FOR Wert wieder hergestellt.
  • Wenn ECHO zu Beginn dieser Phase ist ON, dann 3 Phase) wiederholt, um die geparsten DO Befehle zu zeigen, nachdem die FOR-Variablen erweitert wurde.

---- Von diesem Punkt an jedem Befehl in Phase 2 identifiziert wird getrennt verarbeitet.
---- Phasen 5 bis 7 sind für einen Befehl abgeschlossen, bevor zum nächsten zu bewegen.

Phase 5) Verzögerte Expansion: Nur wenn verzögerte Expansion aktiv ist, ist der Befehl nicht in einem klammern Block auf beiden Seiten eines Rohres , und der Befehl wird kein " nackt“Batch-Skript (Skriptname ohne Klammern, CALL Befehl Verkettung oder Rohr).

  • Jeder Token für einen Befehl wird unabhängig für verzögerte Expansion analysiert.
    • Die meisten Befehle analysierten zwei oder mehr Token - den Befehl Token, die Argumente Token und jede Umleitung Ziel-Token
    • .
    • Die FOR-Befehl analysiert die IN-Klausel nur Token.
    • Der IF-Befehl analysiert die Vergleichswerte nur -. Entweder eine oder zwei, je nach Vergleichsoperator
  • Für jedes geparste Token ist zunächst zu überprüfen, ob es enthält einen !. Wenn nicht, dann wird das Token nicht analysiert - wichtig für ^ Zeichen. Wenn das Token ! enthält, scannen dann jedes Zeichen von links nach rechts:
    • Wenn es ein Caret ist (^) das nächste Zeichen hat keine besondere Bedeutung, die caret selbst entfernt
    • Wenn es ein Ausrufezeichen, Suche nach dem nächsten Ausrufezeichen (Carets werden nicht mehr beobachtet), auf den Wert der Variablen erweitern.
      • konsekutiv Öffnung ! sind in einem einzigen ! kollabiert
      • Ein verbleib ungepaarten ! entfernt
    • Vars Ausbau in diesem Stadium „sicher“ ist, weil Sonderzeichen nicht mehr erkannt werden (auch <CR> oder <LF>)
    • Für eine vollständigere Erklärung, lesen Sie die zweite Hälfte aus dbenham selber Thread - Ausrufezeichen Phase

Phase 5.3) Rohrbearbeitung: Nur wenn Befehle sind auf beiden Seiten eines Rohres
Jede Seite des Rohres bearbeitet werden unabhängig und asynchron.

  • Wenn Befehl intern cmd.exe, oder es ist eine Batchdatei, oder wenn es ein klammerten Befehlsblock ist, dann wird es in einem neuen cmd.exe Faden über %comspec% /S /D /c" commandBlock" ausgeführt, so dass der Befehlsblock einen Phase Neustart bekommt , aber diesmal in Kommandozeilen-Modus.
    • Wenn ein klammerten Befehlsblock, dann all <LF> mit einem Befehl vor und nach zu <space>& umgewandelt. Andere <LF> werden entfernt.
  • Dies ist das Ende der Verarbeitung für die Rohrbefehle.
  • Siehe Warum verzögert Expansion fehlschlagen, wenn innerhalb eines verrohrt Code-Block? für mehr überRohr-Analyse und Verarbeitung

Phase 5.5) ausführen Redirection:. Jede Umleitung, die in Phase entdeckt wurde 2 wird nun ausgeführt

Phase 6) CALL-Verarbeitung / Caret Verdoppelung: Nur wenn der Befehl Token CALL, oder wenn der Text vor dem ersten Standard-Token-Begrenzer auftretenden CALL. Wenn Anruf von einem größeren Befehl Token analysiert wird, dann wird der nicht verwendete Teil wird auf die Argumente vorangestellt, bevor Sie fortfahren Token.

  • Scannen Sie die Argumente für einen nicht notierten /? Token. Wenn irgendwo innerhalb der Token gefunden, dann Abbruch der Phase 6 und fahren Sie mit Phase 7, wo die HELP bei CALL gedruckt werden.
  • Nehmen Sie die erste CALL, so dass mehrere ANRUF die gestapelt werden können
  • Doppel alle Carets
  • Restart Phasen 1, 1,5 und 2, aber nicht weiter Phase 3
    • Jede verdoppelt Carets werden auf ein caret reduziert zurück, solange sie nicht notiert sind. Aber leider zitierte Carets bleiben verdoppelt.
    • Phase 1 ändert sich ein wenig
      • Expansion Fehler in Schritt 1.2 oder 1.3 Abbruch der CALL, aber der Fehler ist nicht tödlich -. Batch-Verarbeitung fortgesetzt
    • Phase-2-Aufgaben sind ein wenig verändert
      • Alle neu erscheinen nicht notierte, unescaped Umleitung, die nicht in der ersten Runde der Phase erkannt wurde 2 erfasst wird, aber es wird entfernt (einschließlich des Dateinamens), ohne tatsächlich die Umleitung durchführen
      • Alle neu erscheint nicht notiert, unescaped caret am Ende der Leitung, ohne eine Zeile Fortsetzung entfernt
      • Der Anruf wird ohne Fehler abgebrochen, wenn eine der folgenden Bedingungen festgestellt werden
        • Neu erscheint nicht notierte, unescaped & oder |
        • Der resultierende Befehl Token beginnt mit nicht notierten, unescaped (
        • Die ersten Token, nachdem der entfernte Anruf mit @ begann
      • Wenn der resultierende Befehl ein scheinbar gültiges IF oder FOR ist, dann wird die Ausführung anschließend mit einem Fehler fehlschlagen, dass IF oder FOR Angabe wird als interner oder externer Befehl nicht erkannt.
      • Natürlich die CALL werden in dieser zweiten Runde der Phase nicht abgebrochen 2, wenn der resultierende Befehl Token wird ein Etikett mit : beginnen.
  • Wenn der resultierende Befehl Token CALL, dann neu starten Phase 6 (wiederholt, bis keine mehr CALL)
  • Wenn der resultierende Befehl Token ein Batch-Skript oder ein: label, dann die Ausführung der CALL wird durch den Rest der Phase 6 vollständig abgewickelt.
    • Drücken Sie die aktuelle Batch-Skript-Datei Position auf dem Call-Stack, so dass die Ausführung von der korrekten Position wieder aufgenommen werden kann, wenn der Anruf beendet ist.
    • Setup die% 0% 1,% 2 ...% N und% * Argument-Tokens für den Anruf unter Verwendung aller resultierenden Tokens
    • Wenn der Befehl Token ein Etikett, das mit : beginnt, dann
      • Restart Phase 5. Dies kann Auswirkungen auf was: Label bezeichnet wird. Da aber die% 0 usw. Token bereits eingerichtet werden, wird es nicht die Argumente ändern, die an die aufgerufene Routine übergeben werden.
      • Ausführen Label GOTO den Dateizeiger auf den Anfang des Unterprogramms zu positionieren (ignorieren alle anderen Token, die möglicherweise folgen: label) Siehe Phase 7 für Regeln, wie GOTO funktioniert.
        • Wenn das: label Token fehlt oder das. Etikett nicht gefunden wird, dann wird der Call-Stack sofort tauchte die gespeicherte Datei Position wiederherzustellen, und der Anruf wird abgebrochen
        • Wenn das: Label: Label enthalten geschieht / ?, dann GOTO Hilfe statt der Suche nach dem gedruckt. Der Dateizeiger bewegt sich nicht, so dass Code nach dem Aufruf wird zweimal ausgeführt, einmal im CALL-Kontext, und dann wieder nach der CALL-Rückkehr. Siehe Warum CALL-druckt die GOTO Hilfemeldung in diesem Skript? Und warum Befehl nach, die zweimal ausgeführt? für weitere Informationen.
    • Else Übertragungssteuerung an die angegebene Batch-Skript.
    • Ausführung des gerufenen: Label oder Skripts wird fortgesetzt, bis entweder EXIT / B oder End-of-Datei erreicht ist, an welchem ??Punkt des CALL-Stapel ausgeklappt ist und die Ausführung wieder aus der gespeicherten Datei Position
      . Phase 7 wird nicht ausgeführt, für CALLed Skripte oder:. Etiketten
  • Else das Ergebnis der Phase 6 fällt durch in Phase 7 zur Ausführung.

Phase 7) ausführen: Der Befehl ausgeführt wird,

  • 7.1 - Führen Sie internen Befehl - Wenn der Befehl Token zitiert wird, dann diesen Schritt überspringen. Ansonsten versuchen, einen internen Befehl zu analysieren und auszuführen.
    • Die folgenden Tests werden gemacht, um zu bestimmen, ob ein unquoted Befehl Token einen internen Befehl darstellt:
      • Wenn der Token Befehl genau einen internen Befehl übereinstimmt, dann ausführen.
      • brechen Else den Befehl Token vor dem ersten Auftreten von + / [ ] <space> <tab> , ; oder =
        Wenn der vorangehende Text ein interner Befehl ist, dann merken, dass der Befehl
        • Wenn im Befehlszeilenmodus, oder wenn der Befehl von einem geklammerten Block ist, wenn sie wahr oder falsch Befehlsblock, Befehlsblock für DO, oder mit dem Befehl Verkettung beteiligt ist, dann führen Sie den internen Befehl
        • Else (muss ein Stand-alone-Befehl im Batch-Modus) scannen die aktuellen Ordner und den Pfad für ein .COM, .EXE, .BAT, oder .cmd-Datei, deren Basisnamen entspricht den ursprünglichen Befehl Token
          • Wenn die erste passende Datei ist eine .BAT oder .cmd, dann gehe zu 7.3.exec und führen Sie das Skript
          • Else (keine Übereinstimmung gefunden oder erstes Spiel ist .EXE oder .COM) führen Sie den erinnerten internen Befehl
      • brechen Else den Befehl Token vor dem ersten Auftreten von . \ oder :
        Wenn der vorhergehende Text nicht ein interner Befehl ist, gehe dann 7,2
        Else vorhergehende Text kann ein interner Befehl sein. Denken Sie daran, diesen Befehl.
      • Brechen Sie den Befehl Token vor dem ersten Auftreten von + / [ ] <space> <tab> , ; oder =
        Wenn der vorhergehende Text ein Pfad zu einer vorhandenen Datei ist, gehe dann 7,2
        Else führen Sie den erinnerten internen Befehl.
    • Wenn ein interner Befehl von einem größeren Befehl Token analysiert wird, dann wird der nicht verwendete Teil der Befehls-Token wird in der Argumentliste enthält
    • Nur weil ein Befehl Token als interner Befehl analysiert wird, bedeutet nicht, dass es erfolgreich ausgeführt wird. Jeder interner Befehl hat seine eigenen Regeln, wie die Argumente und Optionen analysiert werden, und welche Syntax erlaubt.
    • Alle internen Befehle Hilfe Drucken anstatt ihre Funktion erfüllen, wenn /? erkannt wird. Die meisten erkennen /? wenn es überall in den Argumenten erscheint. Aber ein paar Befehle wie ECHO und SET nur Hilfe drucken, wenn das erste Argument Token mit /? beginnt.
    • SET hat einige interessante Semantik:
      • Wenn ein SET-Befehl ein Angebot vor dem Variablennamen und Erweiterungen aktiviert sind
        set "name=content" ignored -> value = content
        dann wird der Text zwischen dem ersten Gleichheitszeichen und dem letzten Zitat als Inhalt verwendet wird (erster und letztes gleich Zitat ausgeschlossen). Text nach dem letzten Zitat wird ignoriert. Wenn es kein Zitat nach dem Gleichheitszeichen ist, dann der Restdie Linie wird als Inhalt verwendet.
      • Wenn ein SET-Befehl nicht über ein Angebot vor dem Namen
        set name="content" not ignored -> value = "content" not ignored
        dann wird der gesamte Rest der Zeile nach dem gleichen, wie Inhalte verwendet wird, jegliche und alle Zitate enthält, die vorhanden sein können.
    • Ein ZF-Vergleich ausgewertet wird, und je nachdem, ob die Bedingung wahr oder falsch ist, wird die entsprechende bereits analysierte abhängiger Befehlsblock verarbeitet wird, mit der Startphase 5.
    • Die IN-Klausel eines FOR-Befehl wird in geeigneter Weise wiederholt.
      • Wenn dies ein FOR / F, das die Ausgabe eines Befehls Block iteriert, dann gilt:
        • Die IN-Klausel wird in einem neuen cmd.exe Prozess über CMD / C ausgeführt.
        • Der Befehlsblock muss den gesamten Parsing-Prozess ein zweites Mal durchlaufen, aber diesmal in einer Befehlszeile Kontext
        • wird ECHO ON beginnen und verzögerte Expansion wird in der Regel beginnen deaktiviert (abhängig von der Registrierungseinstellung)
        • Alle Umgebungsänderungen durch die IN-Klausel Befehlsblock gemacht wird, sobald das Kind cmd.exe Prozess beendet
        • verloren
      • Für jede Iteration:
        • Die für variable Werte sind definiert
        • Der bereits analysierte DO Befehlsblock wird dann verarbeitet, beginnend mit Phase 4.
    • GOTO verwendet die folgende Logik, um die suchen: Label
      • Das Etikett wird von dem ersten Argument analysiert Token
      • Das Skript wird für das nächste Auftreten des Etiketts gescannt
        • Die Scan beginnt, sich von der aktuellen Dateiposition
        • Wenn das Ende der Datei erreicht ist, dann wird die Scan-Schleife zurück zum Anfang der Datei und weiter zum Ausgangspunkt.
      • Die Scan stoppt beim ersten Auftreten des Etiketts, dass es findet, und den Dateizeiger wird unmittelbar auf die Zeile nach dem Etikett. Die Ausführung des Skripts wieder von diesem Punkt aus. Beachten Sie, dass eine erfolgreiche wahr GOTO wird sofort abbrechen jedem geparsten Codeblock, FOR-Schleifen mit.
      • Wenn das Etikett nicht gefunden wird, oder das Etikett Token fehlt, wird dann die GOTO fehlschlägt, wird eine Fehlermeldung ausgegeben, und der Anruf Stapel geknallt. Diese effektiv funktioniert als EXIT / B ist, mit Ausnahme bereits analysiert Befehle in dem aktuellen Befehlsblock, der den GOTO folgen noch ausgeführt werden, sondern im Rahmen des Anrufers (Rahmen, die nach dem EXIT / B existieren)
      • Siehe https://www.dostips.com/forum/ viewtopic.php? f = 3 & t = 3803 für eine genauere Beschreibung der für das Parsen von Etiketten verwendet Regeln.
    • RENAME und COPY beide akzeptieren Platzhalter für die Quell- und Zielpfade. Aber Microsoft hat eine schreckliche Arbeit Dokumentieren, wie die Wildcards arbeiten, vor allem für den Zielpfad. Eine Reihe von nützlichen Wildcard Regeln kann unter finden Wie funktioniert der Windows-Befehl RENAME interpretieren Platzhalter?
  • 7.2 - Ausführen Volumenänderung - Else, wenn der Befehl Token nicht mit einem Zitat beginnt, ist genau zwei Zeichen lang sein, und das zweite Zeichen ist ein Doppelpunkt, dann ist die Lautstärke ändern
    • Alle Argument-Token werden ignoriert
    • Wenn das Volumen durch das erste Zeichen angegeben wird, kann nicht gefunden werden, dann Abbruch mit einem Fehler
    • Ein Befehl von :: Token führt immer zu einem Fehler, es sei denn SUBST verwendet wird, ein Volumen für ::
      zu definieren Wenn SUBST verwendet wird, ein Volumen für :: zu definieren, dann wird die Lautstärke verändert wird, wird es nicht als Etikett behandelt werden.
  • 7.3 - Ausführen externer Befehl - Else versuchen, den Befehl als einen externen Befehl zu behandeln.
    • Wenn im Befehlszeilenmodus und der Befehl nicht zitiert wird, und beginnt nicht mit einem Volumen Spezifikation, brechen dann den Befehl beim ersten Auftreten von Token <space> , ; oder = und prepend der Rest auf das Argument Token (s).
    • Wenn das zweite Zeichen der Befehls-Token ein Doppelpunkt ist, dann das Volumen der ersten angegebenen Zeichen überprüft gefunden werden kann.
      Wenn das Volumen nicht gefunden werden kann, dann Abbruch mit einem Fehler.
    • Wenn im Batch-Modus und der Befehl Token mit : beginnt, dann gehe zu 7,4
      Beachten Sie, dass, wenn das Etikett Token mit :: beginnt, dann wird dies nicht, weil die vorhergehende Stufe mit einem Fehler abgebrochen wird erreicht werden, wenn SUBST ein Volumen für :: zu definieren, verwendet wird.
    • Identifizieren der externe Befehl auszuführen.
      • Dies ist ein komplexer Prozess, der die aktuelle Lautstärke, aktuelles Verzeichnis, PATH-Variable, PATHEXT Variable und oder Dateizuordnungen umfassen.
      • Wenn ein gültiger externer Befehl nicht identifiziert werden kann, dann Abbruch mit einem Fehler.
    • Wenn im Befehlszeilenmodus und den Befehl Token mit : beginnt, dann geh zu 7,4
      Beachten Sie, dass dies nur selten, weil der vorhergehende Schritt erreicht wird, wird mit einem Fehler, es sei denn der Befehl abgebrochen haben Token mit :: beginnt, und SUBST verwendet wird, ein Volumen für :: zu definieren, und das gesamte Kommando-Token ist ein gültiger Pfad zu einem externen Befehl.
    • 7.3.exec -. Führen Sie den externen Befehl
  • 7.4 - Ignorieren ein Label -. Ignorieren Sie den Befehl und alle seine Argumente, wenn der Befehl Token mit : beginnt
    Regeln 7.2 und 7.3 kann ein Etikett erreicht diesen Punkt verhindern.

Command Line Parser:

Arbeiten wie der Batchline-Parser, mit Ausnahme von:

Phase 1) Prozent Expansion:

  • Keine %*, %1 usw. Argument Erweiterung
  • Wenn var nicht definiert ist, %var% bleibt unverändert.
  • Keine besondere Behandlung von %%. Wenn var = Inhalt, dann %%var%% expandiert nach %content%.

Phase 3) Echo des geparsten Befehl (e)

  • Dies ist nicht nach Phase 2 durchgeführt Es wird erst nach Phase 4 durchgeführt für den DO-Befehlsblock.

Phase 5) Verzögerte Expansion: nur, wenn DelayedExpansion aktiviert

  • Wenn var nicht definiert ist, !var! bleibt unverändert.

Phase 7) Befehl ausführen

  • Versuche, ANRUF oder GOTO. A: Label führen zu einem Fehler
  • Wie bereits dokumentiert in Phase 7 ein ausgeführt Etikett in einem Fehler unter verschiedenen Szenarien führen.
    • Batch ausgeführt Etiketten können nur einen Fehler verursachen, wenn sie beginnen, mit ::
    • Befehlszeile ausgeführt Etiketten führen fast immer zu einem Fehler

Parsing von ganzzahligen Werten

Es gibt viele verschiedene Kontexte, in denen cmd.exe Parsen ganzzahlige Werte von Strings, und die Regeln sind inkonsistent:

  • SET /A
  • IF
  • %var:~n,m% (variable Teilzeichenerweiterung)
  • FOR /F "TOKENS=n"
  • FOR /F "SKIP=n"
  • FOR /L %%A in (n1 n2 n3)
  • EXIT [/B] n

Details für diese Regeln können unter Regeln dafür, wie cmd.exe Parsen finden Zahlen


Für alle, die die cmd.exe Parsen Regeln zu verbessern, gibt es eine

Andere Tipps

Wenn ein Befehl von einem Befehlsfenster aufgerufen wird, tokenization der Befehlszeilenargumente nicht durch cmd.exe (auch bekannt als „the shell“) durchgeführt. Am häufigsten wird die tokenization durch die neu gebildeten Prozesse C / C ++ Laufzeit durchgeführt wird, aber dies ist nicht unbedingt so - zum Beispiel, wenn das neue Verfahren nicht in C / C geschrieben wurde ++, oder wenn die neue Prozess wählt argv zu ignorieren und verarbeiten, um die rohe Kommandozeile für sich selbst (zB mit GetCommandLine () ). Auf OS-Ebene, übergibt Windows-Befehlszeilen ungeteilte als einzelne Zeichenfolge an neue Prozesse. Dies steht im Gegensatz zu den meisten * nix-Schalen, in denen die Shell Argumente in einer konsistenten, vorhersagbaren Weise tokenizes bevor sie an den neu gebildeten Prozess vorbei. All dies bedeutet, dass Sie wild divergierende Argument tokenization Verhalten über verschiedene Programme unter Windows auftreten können, wie einzelne Programme oft Argument tokenization selbst in die Hand nehmen.

Wenn es wie Anarchie klingt, es ist eine Art ist. Da jedoch eine große Anzahl von Windows-Programmen tun verwenden, um den Microsoft C / C ++ Laufzeit des argv, kann es in der Regel sinnvoll sein, zu verstehen, , wie die MSVCRT Argumente tokenizes. Hier ein Auszug:

  • Argumente werden durch Leerzeichen begrenzt, die entweder ein Leerzeichen oder eine Registerkarte.
  • Eine Zeichenkette von doppelten Anführungszeichen umgeben ist, als ein einziges Argument interpretiert, unabhängig von Leerraum innerhalb enthalten. Eine Zeichenfolge in Anführungszeichen kann in einem Argument eingebettet werden. Beachten Sie, dass das Einfügemarke (^) nicht als Escape-Zeichen oder Trennzeichen erkannt.
  • A double Zeichen quotation von einem umgekehrten Schrägstrich, \ "ist, wird als Literal doppeltes Anführungszeichen interpretiert (").
  • Umgekehrte Schrägstriche sind buchstäblich interpretiert, es sei denn, sie sofort ein doppeltes Anführungszeichen vorangestellt werden.
  • , wenn eine gerade Anzahl von umgekehrten Schrägstrichen durch ein doppeltes Anführungszeichen gefolgt wird, dann einen umgekehrten Schrägstrich () in der argv Array für jedes Paar von Schrägstrichen gesetzt wird (\) und das doppelte Anführungszeichen ( ") als String interpretiert Trennzeichen.
  • Falls eine ungerade Anzahl von umgekehrten Schrägstrichen durch ein doppeltes Anführungszeichen gefolgt wird, dann einer umgekehrten Schrägstrich () in der argv Array für jedes Paar von Schrägstriche gesetzt wird (\) und das doppelte Anführungszeichen ist als Escape-Sequenz durch die verbleibenden interpretiert Backslash, wodurch ein wörtlichen doppelten Anführungszeichen ( ") in argv platziert werden.

Die Microsoft „Batch-Sprache“ (.bat) ist keine Ausnahme von dieser anarchischen Umgebung, und es hat seine eigenen einzigartigen Regeln für tokenization entwickelt und zu entkommen. Es sieht auch wie Befehl des cmd.exe prompt einige Vorverarbeitung des Befehlszeilenarguments (vor allem für die Variablensubstitution und Flucht) nicht tun, bevor das Argument aus, um den neu ausgeführten Prozeß vorbei. Sie können mehr über die Low-Level-Details der Batch-Sprache lesen und cmd auf dieser Seite in den ausgezeichneten Antworten von jeb und dbenham entkommen.


Wir bauen ein einfaches Kommandozeilenprogramm in C und sehen, was sagt es über Ihre Testfälle:

int main(int argc, char* argv[]) {
    int i;
    for (i = 0; i < argc; i++) {
        printf("argv[%d][%s]\n", i, argv[i]);
    }
    return 0;
}

(Anmerkungen:... Argv [0] ist immer der Name der ausführbaren Datei, und wird im Folgenden der Kürze halber weggelassen Getestet auf Windows XP SP3 Zusammengestellt mit Visual Studio 2005)

> test.exe "a ""b"" c"
argv[1][a "b" c]

> test.exe """a b c"""
argv[1]["a b c"]

> test.exe "a"" b c
argv[1][a" b c]

Und ein paar meiner eigenen Tests:

> test.exe a "b" c
argv[1][a]
argv[2][b]
argv[3][c]

> test.exe a "b c" "d e
argv[1][a]
argv[2][b c]
argv[3][d e]

> test.exe a \"b\" c
argv[1][a]
argv[2]["b"]
argv[3][c]

Percent Regeln der Erweiterung

Hier ist eine erweiterte Erklärung der Phase 1 in jeb Antwort (gültig für Batch-Modus und Kommandozeilen-Modus).

Phase 1) Prozent Erweiterung Beginnend von links, Scannen jedes Zeichen für % oder <LF>. Wenn dann festgestellt,

  • 1,05 (truncate Linie bei <LF>)
    • Wenn das Zeichen <LF> dann
      • Drop (ignorieren), um den Rest der Zeile aus dem <LF> weiter
      • Goto Phase 1.5 (Streifen <CR>)
    • Else das Zeichen muss % sein, gehen Sie so auf 1,1
  • 1.1 (escape %) übersprungen, wenn Kommandozeilen-Modus
    • Wenn Batch-Modus und von einem anderen % gefolgt dann
      Ersetzen %% mit einzelnen % und weiterhin Scan
  • 1.2 (expand Argument) übersprungen, wenn Kommandozeilen-Modus
    • Else wenn Batch-Modus dann
      • Wenn durch * und Befehlserweiterungen gefolgt werden dann
        aktiviert Ersetzen %* mit dem Text aller Befehlszeilenargumente (Ersetzen durch nichts, wenn es keine Argumente) und Scan fortsetzen.
      • Else, wenn sie von <digit> gefolgt dann
        Ersetzen %<digit> mit Argumentwert (ersetzen mit nichts, wenn nicht definiert) und weiter Scan.
      • Else gefolgt, wenn sie von ~ und Befehlserweiterungen aktiviert sind dann
        • Wenn durch optionale gültige Liste von Argumenten Modifikatoren gefolgt von erforderlichen <digit> gefolgt dann
          Ersetzen %~[modifiers]<digit> mit modifizierten Argumentwert (ersetzen mit nichts, wenn nicht definiert oder wenn $ PATH angegeben: Modifikator nicht definiert ist). Und weiter Scan
          Hinweis: Modifikatoren sind Groß- und Kleinschreibung und mehrfach in beliebiger Reihenfolge auftreten können, außer $ PATH: Modifikator nur einmal vorkommen kann und muss der letzte Modifikator vor dem <digit> sein
        • Else ungültig geändert Argument Syntax Raises fatale Fehler: Alle analysierten Befehle abgebrochen werden, und die Stapelverarbeitung wird abgebrochen, wenn im Batch-Modus
  • 1.3 (erweitern Variable)
    • Else Wenn die Befehlserweiterungen deaktiviert werden dann
      Schauen Sie bei der nächsten Folge von Zeichen, brechen vor % oder Ende des Puffers, und nennen sie VAR (kann eine leere Liste sein)
      • Wenn nächste Zeichen % dann
        • Wenn VAR definiert wird dann
          Ersetzen %VAR% mit dem Wert von VAR und weiterhin Scan
        • Else wenn Batch-Modus dann
          Entfernen %VAR% und weiterhin Scan
        • Else Goto 1.4
      • Else Goto 1.4
    • Else Wenn die Befehlserweiterungen aktiviert sind dann
      Schauen Sie bei der nächsten Folge von Zeichen, brechen vor % : oder Ende des Puffers, und nennen sie VAR (kann eine leere Liste sein). Wenn VAR Pausen vor : und das nachfolgende Zeichen ist % dann schließen : als das letzte Zeichen in VAR und brechen vor %.
      • Wenn nächste Zeichen % dann
        • Wenn VAR definiert wird dann
          Ersetzen %VAR% mit dem Wert von VAR und weiterhin Scan
        • Else wenn Batch-Modus dann
          Entfernen %VAR% und weiterhin Scan
        • Else Goto 1.4
      • Else wenn nächste Zeichen : dann
        • ist, wenn VAR undefined dann
          • Wenn Batch-Modus dann
            Entfernen %VAR: und weiterhin Scan.
          • Else Goto 1.4
        • Else wenn nächste Zeichen ~ dann
          • Wenn nächste Zeichenfolge entspricht Muster von [integer][,[integer]]% dann
            ersetzen %VAR:~[integer][,[integer]]% mit String Wert von VAR (möglicherweise in leeren String führt) und weiterhin Scan.
          • Else Goto 1.4
        • Else gefolgt, wenn sie von = oder *= dann
          Unzulässige Variable Suchen und Ersetzen-Syntax Raises fatale Fehler: Alle analysierten Befehle werden abgebrochen, und die Stapelverarbeitung wird abgebrochen, wenn im Batch-Modus
        • Else wenn nächste Zeichenfolge Muster von [*]search=[replace]% übereinstimmt, wo suchen eine beliebige Menge von Zeichen mit Ausnahme = enthalten kann, und ersetzen Sie können eine beliebige Menge von Zeichen mit Ausnahme % enthalten, dann ersetzen
          %VAR:[*]search=[replace]% mit dem Wert von VAR nach Suche durchführen und ersetzen (möglicherweise in leeren String führt) und weiter Scan
        • Else Goto 1.4
  • 1,4 (Streifen%)
    • Else Wenn Batch-Modus dann
      Entfernen % und weiter Scan beginnend mit dem nächsten Zeichen nach dem %
    • Else erhalten %and weiterhin Scan beginnend mit dem nächsten Zeichen nach dem %

Das oben erklärt, warum diese Charge

@echo off
setlocal enableDelayedExpansion
set "1var=varA"
set "~f1var=varB"
call :test "arg1"
exit /b  
::
:test "arg1"
echo %%1var%% = %1var%
echo ^^^!1var^^^! = !1var!
echo --------
echo %%~f1var%% = %~f1var%
echo ^^^!~f1var^^^! = !~f1var!
exit /b

Gibt diese Ergebnisse:

%1var% = "arg1"var
!1var! = varA
--------
%~f1var% = P:\arg1var
!~f1var! = varB

Hinweis 1 - Phase 1 tritt vor der Anerkennung der REM-Anweisungen. Dies ist sehr wichtig, weil es bedeutet auch eine Bemerkung, kann zu einem schwerwiegenden Fehler erzeugen, wenn es ungültig Argument Erweiterung Syntax oder ungültige Variable Suchen und Ersetzen-Syntax hat!

@echo off
rem %~x This generates a fatal argument expansion error
echo this line is never reached

Hinweis 2 - Eine weitere interessante Konsequenz der% Parsen Regeln: Variablen enthalten: im Namen definiert werden, aber sie können nicht erweitert werden, es sei denn, Befehlserweiterungen deaktiviert sind. Es gibt eine Ausnahme - ein Variablenname einen einzigen Doppelpunkt am Ende enthält, erweitert werden kann, während Befehlserweiterungen aktiviert sind. Sie können jedoch nicht durchführen oder nach Teilzeichen und Ersetzen-Operationen auf Variablennamen mit einem Doppelpunkt enden. Die Batch-Datei unten (mit freundlicher Genehmigung von jeb) zeigt dieses Verhalten

@echo off
setlocal
set var=content
set var:=Special
set var::=double colon
set var:~0,2=tricky
set var::~0,2=unfortunate
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%
echo Now with DisableExtensions
setlocal DisableExtensions
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%

Hinweis 3 - Ein interessantes Ergebnis der Reihenfolge der Parsing-Regeln, dass jeb in seinem Amt legt: Bei Suchabfrage durchführen und ersetzen mit einem verzögerten Expansion, Sonderzeichen in beide finden und ersetzen Bedingungen müssen entkommen oder zitiert werden. Aber die Situation ist anders für die prozentuale Expansion - der Fund Begriff darf nicht entwertet werden (obwohl es kann angegeben werden). Der Prozentsatz ersetzt Zeichenfolge kann oder auch nicht entkommen oder Zitat benötigen, abhängig von Ihrer Absicht.

@echo off
setlocal enableDelayedExpansion
set "var=this & that"
echo %var:&=and%
echo "%var:&=and%"
echo !var:^&=and!
echo "!var:&=and!"

Delayed Erweiterungsregeln

Hier ist eine erweiterte und eine genauere Erklärung der Phase 5 in jeb Antwort (gilt für beide Batch-Modus und Befehl Zeilenmodus)

Phase 5) Verzögerte Erweiterung

Diese Phase übersprungen wird, wenn eine der folgenden Bedingungen zutreffen:

  • Verzögerte Erweiterung ist deaktiviert.
  • Der Befehl ist innerhalb eines geklammerten Block auf beiden Seiten eines Rohres.
  • Der ankommende Befehl Token ist ein "nackter" Batch-Skript, das heißt, es nicht mit CALL, geklammerten Block, jede Form von Befehl Verkettung (&, && oder ||) oder einem Rohr | zugeordnet ist.

Der verzögerte Expansionsprozess wird auf Token unabhängig angewendet. Ein Befehl kann mehrere Token haben:

  • Der Befehl Token. Für die meisten Befehle der Befehlsname selbst ist ein Token. Aber ein paar Befehle haben Regionen spezialisiert, die eine TOKEN für Phase 5 betrachtet werden.
    • for ... in(TOKEN) do
    • if defined TOKEN
    • if exists TOKEN
    • if errorlevel TOKEN
    • if cmdextversion TOKEN
    • if TOKEN comparison TOKEN, wo Vergleich eines von == ist, equ, neq, lss, leq, gtr oder geq
  • Die Argumente Token
  • Das Ziel Zeichen der Umleitung (eine pro-Umleitung)

Keine Änderung Token gemacht wird, die nicht ! enthalten.

Für jedes Token, das mindestens eine ! enthält, Scannen jedes Zeichen von links nach rechts für ^ oder !, und wenn gefunden, dann

  • 5.1 (caret Escape) für ! oder ^ Literale benötigt
    • Wenn Zeichen ein caret ^ dann
      • Entfernen Sie die ^
      • Scan das nächste Zeichen und bewahren sie als wörtliche
      • Weiter den Scan
  • 5.2 (expand Variable)
    • Wenn Zeichen !, dann
      • Wenn die Befehlserweiterungen sind deaktiviert dann
        Schauen Sie bei der nächsten Folge von Zeichen, brechen vor ! oder <LF>, und nennen sie VAR (kann eine leere Liste sein)
        • Wenn nächste Zeichen ! dann
          • Wenn VAR definiert ist, dann
            Ersetzen !VAR! mit dem Wert von VAR und weiterhin Scan
          • Else wenn Batch-Modus dann
            Entfernen !VAR! und weiterhin Scan
          • Else Goto 5.2.1
        • Else Goto 5.2.1
      • Else Wenn die Befehlserweiterungen aktiviert sind dann
        Schauen Sie bei der nächsten Folge von Zeichen, brechen vor !, : oder <LF>, und nennen sie VAR (kann eine leere Liste sein). Wenn VAR Pausen vor : und das nachfolgende Zeichen ist ! dann schließen : als das letzte Zeichen in VAR und brechen vor !
        • Wenn nächste Zeichen ! dann
          • Wenn VAR existiert, dann
            Ersetzen !VAR! mit dem Wert von VAR und weiterhin Scan
          • Else wenn Batch-Modus dann
            Entfernen !VAR! und weiterhin Scan
          • Else Goto 5.2.1
        • Else wenn nächste Zeichen : dann
          • ist, wenn VAR undefined dann
            • Wenn Batch-Modus dann
              Entfernen !VAR: und weiterhin Scan
            • Else Goto 5.2.1
          • Else wenn nächste Zeichenfolge entspricht Muster von
            ~[integer][,[integer]]! dann
            Ersetzen !VAR:~[integer][,[integer]]! mit String Wert von VAR (möglicherweise in einem leeren String führt) und weiter Scan
          • Else wenn nächste Zeichenfolge entspricht Muster von [*]search=[replace]!, wo suchen eine beliebige Menge von Zeichen mit Ausnahme = enthalten kann, und ersetzen Sie können eine beliebige Menge von Zeichen außer ! umfassen, dann
            Ersetzen !VAR:[*]search=[replace]! mit dem Wert von VAR nach Suche durchführen und ersetzen (möglicherweise in einem leeren String führt) und weiter Scan
          • Else Goto 5.2.1
        • Else Goto 5.2.1
      • 5.2.1
        • Wenn Batch-Modus und entfernen Sie die !
          Else Erhaltung der !
        • Weiter den Scan beginnend mit dem nächsten Zeichen nach dem !

Wie bereits ausgeführt, sind Befehle, um die gesamte Argument Zeichenfolge in µSoft Land übergeben, und es ist ihnen bis zu analysieren diese in separate Argumente für den eigenen Gebrauch. Es gibt keine consistencty in diesem zwischen verschiedenen Programmen, und deshalb gibt es keine von Regeln festgelegt, diesen Prozess zu beschreiben. Sie müssen wirklich jede Ecke Fall für jede Art C-Bibliothek Ihres Programm überprüfen.

Was die System .bat Dateien gehen, hier ist, dass Test:

c> type args.cmd
@echo off
echo cmdcmdline:[%cmdcmdline%]
echo 0:[%0]
echo *:[%*]
set allargs=%*
if not defined allargs goto :eof
setlocal
@rem Wot about a nice for loop?
@rem Then we are in the land of delayedexpansion, !n!, call, etc.
@rem Plays havoc with args like %t%, a"b etc. ugh!
set n=1
:loop
    echo %n%:[%1]
    set /a n+=1
    shift
    set param=%1
    if defined param goto :loop
endlocal

Jetzt können wir ein paar Tests durchführen. Sehen Sie, wenn Sie herausfinden können, was µSoft versuchen zu tun:

C>args a b c
cmdcmdline:[cmd.exe ]
0:[args]
*:[a b c]
1:[a]
2:[b]
3:[c]

Fine bisher. (Ich werde das uninteressant %cmdcmdline% und %0 von nun auslassen auf.)

C>args *.*
*:[*.*]
1:[*.*]

Keine Dateinamen Expansion.

C>args "a b" c
*:["a b" c]
1:["a b"]
2:[c]

Kein Zitat Strippen, obwohl Anführungszeichen Argument Splitting tun verhindern.

c>args ""a b" c
*:[""a b" c]
1:[""a]
2:[b" c]

konsekutiv doppelte Anführungszeichen bewirkt, dass sie spezielle Parsing Fähigkeiten verlieren sie gehabt haben können. @ Beniot das Beispiel:

C>args "a """ b "" c"""
*:["a """ b "" c"""]
1:["a """]
2:[b]
3:[""]
4:[c"""]

Quiz: Wie übergeben Sie den Wert jeder Umgebung var als Single Argument (das heißt, als %1) zu einer Bat-Datei

c>set t=a "b c
c>set t
t=a "b c
c>args %t%
1:[a]
2:["b c]
c>args "%t%"
1:["a "b]
2:[c"]
c>Aaaaaargh!

Sane Parsing scheint für immer gebrochen.

Für Ihre Unterhaltung, versuchen Sie, verschiedene ^, \, ', & (usw.) Zeichen auf diese Beispiele.

Sie haben einige große Antworten oben schon, aber ein Teil Ihrer Frage zu beantworten:

set a =b, echo %a %b% c% → bb c%

Was dort geschieht, ist, dass, weil Sie ein Leerzeichen vor dem haben = eine Variable erstellt wird genannt %a<space>% so, wenn Sie echo %a % das richtig als b ausgewertet wird.

Der restliche Teil b% c% wird dann als Klartext + eine nicht definierte Variable % c% ausgewertet, die als getippt hallte werden soll, für mich kehrt echo %a %b% c% bb% c%

Ich vermute, dass die Fähigkeit, in Variablennamen Leerzeichen enthalten ist eher ein Versehen als ein geplanten ‚Feature‘

bearbeiten. Siehe akzeptierte Antwort, was folgt, ist falsch und erklärt nur, wie eine Befehlszeile an TinyPerl passieren


In Bezug auf Zitate, habe ich das Gefühl, dass das Verhalten ist die folgende:

  • , wenn ein " gefunden wird, string Globbing beginnt
  • wenn Zeichenfolge Kleckse auftreten:
    • jedes Zeichen, das kein " ist globbed
    • , wenn ein " gefunden wird:
      • , wenn sie von "" (also eine dreifache ") dann ein doppeltes Anführungszeichen hinzugefügt wird mit dem String folgt
      • , wenn sie von " (also eine doppelte ") dann ein doppeltes Anführungszeichen hinzugefügt wird, um den String und String Globbing Enden folgt
      • , wenn das nächste Zeichen nicht ", string Globbing Ende
    • , wenn die Leitungsenden, Schnur Globbing endet.

Kurz gesagt:

"a """ b "" c""" besteht aus zwei Saiten: a " b " und c"

"a"", "a""" and"a"""" sind alle gleich String, wenn am Ende einer Zeile

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top