Ich bin auf ss64.com gestoßen, das eine gute Hilfe zum Schreiben von Batch-Skripten bietet, die der Windows- Befehlsinterpreter ausführen wird.
Ich konnte jedoch keine gute Erklärung für die Grammatik finden von Batch-Skripten finden, wie sich Dinge erweitern oder nicht erweitern und wie man Dingen entgeht.
Hier sind Beispielfragen, die ich nicht lösen konnte:
- Wie wird das Angebotssystem verwaltet? Ich habe ein TinyPerl- Skript
(foreach $i (@ARGV) { print '*' . $i ; }
) erstellt, es kompiliert und folgendermaßen aufgerufen:my_script.exe "a ""b"" c"
→ Ausgabe ist*a "b*c
my_script.exe """a b c"""
→ ausgeben*"a*b*c"
- Wie funktioniert das interne
echo
Befehl? Was wird in diesem Befehl erweitert? - Warum muss ich
for [...] %%I
in Dateiskripten aber verwendenfor [...] %I
in interaktiven Sitzungen verwenden? - Was sind die Fluchtzeichen und in welchem Kontext? Wie entkomme ich einem Prozentzeichen? Wie kann ich zum Beispiel
%PROCESSOR_ARCHITECTURE%
buchstäblich widerhallen ? ich habe das gefundenecho.exe %""PROCESSOR_ARCHITECTURE%
funktioniert, gibt es eine bessere Lösung? - Wie
%
passen Paare zusammen? Beispiel:set b=a
,echo %a %b% c%
→%a a c%
set a =b
,echo %a %b% c%
→bb c%
- Wie stelle ich sicher, dass eine Variable als einzelnes Argument an einen Befehl übergeben wird, wenn diese Variable jemals doppelte Anführungszeichen enthält?
- Wie werden Variablen bei Verwendung des
set
Befehls gespeichert ? Zum Beispiel, wenn ich es tueset a=a" b
und dannecho.%a%
erhalte icha" b
. Wenn ich jedochecho.exe
von den UnxUtils benutze, bekomme icha b
. Wie kommt es, dass%a%
sich das anders ausdehnt?
Danke für deine Lichter.
Antworten:
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>
.<Ctrl-Z>
(0x1A) als gelesen<LF>
(LineFeed 0x0A)<Ctrl-Z>
, wird es als sich selbst behandelt - es wird nicht in konvertiert<LF>
Phase 1) Prozentuale Expansion:
%%
wird durch ein Einzel ersetzt%
%*
,%1
,%2
, etc.)%var%
, wenn var nicht existiert, ersetzen Sie es durch nichts<LF>
nicht innerhalb der%var%
Erweiterung abgeschnittenPhase 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.
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
und<0xFF>
aufeinanderfolgende Token-Begrenzer werden als eins behandelt. Zwischen den Token-Begrenzern befinden sich keine leeren Token
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:
<CR>
dann entfernen Sie es, als ob es nie da wäre (außer für seltsames Umleitungsverhalten )^
) wird das nächste Zeichen maskiert und das entkommende Caret entfernt. Entkommene Zeichen verlieren jede besondere Bedeutung (außer<LF>
)."
), 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>
.<LF>
<LF>
wird abgestreift<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.<LF>
einem FOR IN-Klammerblock nicht entkommen<LF>
wird in a umgewandelt<space>
<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.&
|
<
oder>
, teilen Sie die Zeile an dieser Stelle, um Pipes, Befehlsverkettung und Umleitung zu verarbeiten.|
) ist jede Seite ein separater Befehl (oder Befehlsblock), der in Phase 5.3 eine spezielle Behandlung erhält&
,&&
oder||
Befehlsverkettung, wobei jede Seite der Verkettung wird als separater Befehl behandelt.<
,<<
,>
, 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.@
, hat das@
eine besondere Bedeutung. (@
ist in keinem anderen Kontext etwas Besonderes)@
wird entfernt.@
vor einer Öffnung(
, wird der gesamte Block in Klammern vom Phase-3-Echo ausgeschlossen.(
ist dies nichts Besonderes.(
, starten Sie eine neue zusammengesetzte Anweisung und erhöhen Sie den Klammerzähler)
, wird die zusammengesetzte Anweisung beendet und der Klammerzähler dekrementiert.)
funktioniert er ähnlich wie eineREM
Anweisung, solange unmittelbar darauf ein Token-Trennzeichen, ein Sonderzeichen, eine neue Zeile oder ein Dateiende folgt^
(Zeilenverkettung ist möglich)@
und die Umleitung an das Ende verschoben wurde).(
zusätzlich zu den Standard-Token-Trennzeichen als Befehlstoken-Begrenzer<LF>
als<space>
. Nachdem die IN-Klausel analysiert wurde, werden alle Token zu einem einzigen Token zusammengefasst.^
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^
.:
und dies die erste Runde von Phase 2 ist (kein Neustart aufgrund von CALL in Phase 6), dann)
,<
,>
,&
und|
nicht mehr hat eine besondere Bedeutung. Der gesamte Rest der Zeile wird als Teil der Bezeichnung "Befehl" betrachtet.^
weiterhin etwas Besonderes, dh die Zeilenfortsetzung kann verwendet werden, um die nachfolgende Zeile an das Etikett anzuhängen.(
hat keine besondere Bedeutung mehr für den ersten Befehl, der auf das nicht ausgeführte Label folgt .|
Rohr oder&
,&&
oder||
Befehlsverkettung auf der Linie.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.%%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.~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.---- 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).
!
. Wenn nicht, wird das Token nicht analysiert - wichtig für^
Zeichen. Wenn das Token enthält!
, scannen Sie jedes Zeichen von links nach rechts:^
) handelt, hat das nächste Zeichen keine besondere Bedeutung, das Caret selbst wird entfernt!
werden zu einer einzigen zusammengefasst!
!
werden entfernt<CR>
oder<LF>
)Phase 5.3) Rohrverarbeitung: Nur wenn sich Befehle auf beiden Seiten eines Rohrs befinden
Jede Seite des Rohrs wird unabhängig und asynchron verarbeitet.
%comspec% /S /D /c" commandBlock"
, sodass der Befehlsblock einen Phasenneustart erhält, diesmal jedoch im Befehlszeilenmodus.<LF>
mit einem Befehl davor und danach in konvertiert<space>&
. Andere<LF>
werden abgestreift.Phase 5.5) Umleitung ausführen: Jede in Phase 2 erkannte Umleitung wird jetzt ausgeführt.
||
verwendet wird .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.
/?
. 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.CALL
, damit mehrere CALLs gestapelt werden können&
oder|
(
@
IF
oderFOR
nicht.:
.:
, dannPhase 7 wird nicht für aufgerufene Skripte oder: Labels ausgeführt.
Phase 7) Ausführen: Der Befehl wird ausgeführt
+
/
[
]
<space>
<tab>
,
;
oder.=
Wenn der vorhergehende Text ein interner Befehl ist, merken Sie sich diesen Befehl
.
\
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.
+
/
[
]
<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.
/?
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 "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.
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.
::
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.,
,;
,=
oder+
dann den Befehl beim ersten Auftreten Token brechen von<space>
,
;
oder=
und stellen Sie vor dem Rest das Argument Token (s).Wenn das Volume nicht gefunden werden kann, brechen Sie den Vorgang mit einem Fehler ab.
:
, 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::
.:
, 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.:
.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:
%*
,%1
usw. Argument Expansion%var%
ist, bleibt es unverändert.%%
. Wenn var = content, wird auf%%var%%
erweitert%content%
.Phase 3) Geben Sie die analysierten Befehle wieder.
Phase 5) Verzögerte Erweiterung: Nur wenn DelayedExpansion aktiviert ist
!var!
ist, bleibt es unverändert.Phase 7) Befehl ausführen
::
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
quelle
)
funktioniert wirklich fast wie einREM
Befehl, wenn der Klammerzähler 0 ist. Versuchen Sie beide über die Befehlszeile :) Ignore this
, undecho OK & ) Ignore this
Wenn Sie einen Befehl über ein Befehlsfenster aufrufen, erfolgt die Tokenisierung der Befehlszeilenargumente nicht durch
cmd.exe
(auch als "Shell" bezeichnet). Meistens erfolgt die Tokenisierung über die C / C ++ - Laufzeit der neu gebildeten Prozesse. Dies ist jedoch nicht unbedingt der Fall - beispielsweise, wenn der neue Prozess nicht in C / C ++ geschrieben wurde oder wenn der neue Prozess ignoriertargv
und verarbeitet die rohe Kommandozeile für sich selbst (zB mit GetCommandLine ()). Auf Betriebssystemebene übergibt Windows Befehlszeilen, die nicht als einzelne Zeichenfolge gekennzeichnet sind, an neue Prozesse. Dies steht im Gegensatz zu den meisten * nix-Shells, bei denen die Shell Argumente auf konsistente, vorhersehbare Weise tokenisiert, bevor sie an den neu gebildeten Prozess übergeben werden. All dies bedeutet, dass das Verhalten der Tokenisierung von Argumenten in verschiedenen Programmen unter Windows sehr unterschiedlich sein kann, da einzelne Programme die Tokenisierung von Argumenten häufig selbst in die Hand nehmen.Wenn es nach Anarchie klingt, ist es das auch. Da jedoch eine große Anzahl von Windows - Programmen zu tun , die Microsoft C / C ++ Laufzeit des nutzen
argv
, kann es in der Regel sinnvoll sein , zu verstehen , wie die MSVCRT tokenizes Argumente. Hier ist ein Auszug:Die "Batch-Sprache" (
.bat
) von Microsoft ist keine Ausnahme von dieser anarchischen Umgebung und hat eigene eindeutige Regeln für die Tokenisierung und das Escapezeichen entwickelt. Es sieht auch so aus, als würde die Eingabeaufforderung von cmd.exe das Befehlszeilenargument vorverarbeiten (hauptsächlich zum Ersetzen und Escapezeichen von Variablen), bevor das Argument an den neu ausgeführten Prozess übergeben wird. Weitere Informationen zu den Details der Batch-Sprache und des Cmd auf niedriger Ebene finden Sie in den hervorragenden Antworten von jeb und dbenham auf dieser Seite.Lassen Sie uns ein einfaches Befehlszeilenprogramm in C erstellen und sehen, was es über Ihre Testfälle aussagt:
(Hinweise: argv [0] ist immer der Name der ausführbaren Datei und wird der Kürze halber unten weggelassen. Getestet unter Windows XP SP3. Kompiliert mit Visual Studio 2005.)
Und einige meiner eigenen Tests:
quelle
[a "b" c]
es zur[a "b] [c]
Nachbearbeitung kommen kann.GetCommandLine
. B. Win32 abrufen . Vielleicht ignoriert TinyPerl argv und markiert die rohe Befehlszeile einfach nach eigenen Regeln.Prozent Expansionsregeln
Hier ist eine erweiterte Erklärung von Phase 1 in Jebs Antwort (gültig sowohl für den Batch-Modus als auch für den Befehlszeilenmodus).
Phase 1) Prozentuale Erweiterung Scannen Sie von links nach jedem Zeichen nach
%
oder<LF>
. Wenn dann gefunden<LF>
)<LF>
dann ist<LF>
an fallen (ignorieren)<CR>
)%
, fahren Sie also mit 1.1 fort%
) wird im Befehlszeilenmodus übersprungen%
dann durch Singleersetzen und den Scan fortsetzen
%%
%
*
und Befehlserweiterungen aktiviert sind,ersetzen Sie
%*
durch den Text aller Befehlszeilenargumente (Ersetzen durch nichts, wenn keine Argumente vorhanden sind) und fahren Sie mit dem Scannen fort.<digit>
dannErsetzen
%<digit>
mit Argumentwert (mit nichts ersetzen , wenn nicht definiert) und Scan fortsetzen.~
Befehlserweiterungen aktiviert, wenn gefolgt von und<digit>
dannErsetzen
%~[modifiers]<digit>
mit modifizierten Argument - Wert (mit nichts ersetzen , wenn nicht definiert oder wenn $ PATH angegeben: Modifikator nicht definiert ist ) und Scan fortsetzen.Hinweis: Modifikatoren unterscheiden nicht zwischen Groß- und Kleinschreibung und können in beliebiger Reihenfolge mehrmals angezeigt werden, mit Ausnahme von $ PATH: Der Modifikator kann nur einmal angezeigt werden und muss der letzte Modifikator vor dem sein
<digit>
schauen Sie sich die nächste Zeichenfolge an, die vor
%
oder am Ende des Puffers unterbrochen wird , und nennen Sie sie VAR (möglicherweise eine leere Liste).%
dann istersetzen Sie
%VAR%
durch VAR und setzen Sie den Scan fortentfernen
%VAR%
und den Scan fortsetzenschauen Sie sich die nächste Zeichenfolge an, die vor
%
:
oder am Ende des Puffers unterbrochen wird , und nennen Sie sie VAR (möglicherweise eine leere Liste). Wenn VAR Pausen vor:
und die nachfolgenden Zeichen%
umfassen dann:
als letztes Zeichen in VAR und Pause vor%
.%
dann istersetzen Sie
%VAR%
durch VAR und setzen Sie den Scan fortentfernen
%VAR%
und den Scan fortsetzen:
dann istentfernen
%VAR:
und den Scan fortsetzen.~
dann ist[integer][,[integer]]%
dannErsetzen
%VAR:~[integer][,[integer]]%
mit String Wert von VAR (möglicherweise in leeren String führt) und Scan fortsetzen.=
oder*=
dannUnzulässige Variable Suchen und Ersetzen - Syntax werfen fatale Fehler: Alle analysierten Befehle werden abgebrochen, und die Stapelverarbeitung wird abgebrochen , wenn im Batch - Modus!
[*]search=[replace]%
, wobei die Suche einen beliebigen Zeichensatz außer=
und das Ersetzen einen beliebigen Zeichensatz außer enthalten kann%
,ersetzen Sie
%VAR:[*]search=[replace]%
nach dem Suchen und Ersetzen durch den Wert VAR (was möglicherweise zu einer leeren Zeichenfolge führt) und fahren Sie fort ScanEntfernen Sie den
%
Scan und setzen Sie ihn fort, beginnend mit dem nächsten Zeichen nach dem%
%
und setzen den Scan fort, beginnend mit dem nächsten Zeichen nach der erhaltenen Führung%
Das Obige hilft zu erklären, warum diese Charge
Gibt diese Ergebnisse:
Anmerkung 1 - Phase 1 erfolgt vor der Erkennung von REM-Anweisungen. Dies ist sehr wichtig, da selbst eine Bemerkung einen schwerwiegenden Fehler verursachen kann, wenn sie eine ungültige Argumenterweiterungssyntax oder eine ungültige Such- und Ersetzungssyntax für Variablen aufweist!
Hinweis 2 - Eine weitere interessante Konsequenz der% parsing-Regeln: Variablen, die: im Namen enthalten, können definiert, aber nur erweitert werden, wenn die Befehlserweiterungen deaktiviert sind. Es gibt eine Ausnahme: Ein Variablenname, der am Ende einen einzelnen Doppelpunkt enthält, kann erweitert werden, während Befehlserweiterungen aktiviert sind. Sie können jedoch keine Teilzeichenfolgen oder Such- und Ersetzungsvorgänge für Variablennamen ausführen, die mit einem Doppelpunkt enden. Die folgende Batch-Datei (mit freundlicher Genehmigung von jeb) zeigt dieses Verhalten
Anmerkung 3 - Ein interessantes Ergebnis der Reihenfolge der Parsing-Regeln, die jeb in seinem Beitrag festlegt: Wenn Sie Suchen und Ersetzen mit verzögerter Erweiterung ausführen, müssen Sonderzeichen sowohl in den Begriffen Suchen als auch Ersetzen maskiert oder in Anführungszeichen gesetzt werden. Bei der prozentualen Expansion ist die Situation jedoch anders - der Suchbegriff darf nicht maskiert werden (obwohl er zitiert werden kann). Die prozentuale Ersetzungszeichenfolge erfordert je nach Ihrer Absicht möglicherweise ein Escape- oder Anführungszeichen.
Verzögerte Erweiterungsregeln
Hier ist eine erweiterte und genauere Erklärung von Phase 5 in Jebs Antwort (gültig sowohl für den Batch-Modus als auch für den Befehlszeilenmodus).
Phase 5) Verzögerte Expansion
Diese Phase wird übersprungen, wenn eine der folgenden Bedingungen zutrifft:
CALL
, geklammerten Block, jede Form von Befehlsverkettung (&
,&&
oder||
) oder ein Rohr|
.Der verzögerte Expansionsprozess wird unabhängig auf Token angewendet. Ein Befehl kann mehrere Token haben:
for ... in(TOKEN) do
if defined TOKEN
if exists TOKEN
if errorlevel TOKEN
if cmdextversion TOKEN
if TOKEN comparison TOKEN
, In dem Vergleich ein von==
,equ
,neq
,lss
,leq
,gtr
, odergeq
Token, die keine enthalten, werden nicht geändert
!
.!
Scannen Sie für jedes Token, das mindestens eines enthält , jedes Zeichen von links nach rechts nach^
oder!
, und falls gefunden, dann!
oder^
Literale^
dann^
!
, dannschauen Sie sich die nächste Zeichenfolge an, die vor
!
oder unterbrochen wird<LF>
, und nennen Sie sie VAR (möglicherweise eine leere Liste).!
dann istersetzen Sie
!VAR!
durch VAR und setzen Sie den Scan fortentfernen
!VAR!
und den Scan fortsetzenanschauen nächste Folge von Zeichen, brechen vor
!
,:
oder<LF>
, und nennen sie VAR (kann eine leere Liste sein). Wenn VAR Pausen vor:
und die nachfolgenden Zeichen!
umfassen dann:
als letztes Zeichen in VAR und Pause vor!
!
dann istersetzen Sie
!VAR!
durch den Wert VAR und fahren Sie mit dem Scannen fortEntfernen
!VAR!
und den Scan fortsetzen:
dann istEntfernen
!VAR:
und den Scan fortsetzen~
dann ist[integer][,[integer]]!
ersetzen Sie sie!VAR:~[integer][,[integer]]!
durch eine Teilzeichenfolge mit dem Wert VAR (was möglicherweise zu einer leeren Zeichenfolge führt) und fahren Sie mit dem Scannen fort.[*]search=[replace]!
, wobei die Suche einen beliebigen Zeichensatz außer=
und das Ersetzen einen beliebigen Zeichensatz außer enthalten kann!
, dannErsetzen
!VAR:[*]search=[replace]!
nach dem Suchen und durch den Wert VAR (was möglicherweise zu einer leeren Zeichenfolge führt) und Scan fortsetzen!
Andernfalls behalten Sie das führende bei
!
!
quelle
%definedVar:a=b%
vs%undefinedVar:a=b%
und die%var:~0x17,-010%
Formulare%<digit>
,%*
oder%~
. Und das Verhalten ändert sich für undefinierte Variablen. Vielleicht müssen Sie eine zweite Antwort öffnenWie bereits erwähnt, wird Befehlen die gesamte Argumentzeichenfolge in μSoft Land übergeben, und es liegt an ihnen, diese für ihren eigenen Gebrauch in separate Argumente zu zerlegen. Es gibt keine Übereinstimmung zwischen verschiedenen Programmen, und daher gibt es keine Regeln, die diesen Prozess beschreiben. Sie müssen wirklich jeden Eckfall auf die von Ihrem Programm verwendete C-Bibliothek überprüfen.
Was die Systemdateien
.bat
betrifft, ist hier dieser Test:Jetzt können wir einige Tests durchführen. Sehen Sie, ob Sie herausfinden können, was μSoft versucht:
Bis jetzt gut. (Ich werde das Uninteressante weglassen
%cmdcmdline%
und%0
von nun an.)Keine Dateinamenerweiterung.
Kein Entfernen von Anführungszeichen, obwohl Anführungszeichen das Aufteilen von Argumenten verhindern.
Aufeinanderfolgende doppelte Anführungszeichen führen dazu, dass sie ihre speziellen Analysefähigkeiten verlieren. @ Beniots Beispiel:
Quiz: Wie übergeben Sie den Wert einer Umgebungsvariablen als einzelnes Argument (dh als
%1
) an eine Bat-Datei?Vernünftiges Parsen scheint für immer gebrochen zu sein.
Für Ihre Unterhaltung, versuchen Sie , verschiedene
^
,\
,'
,&
(usw.) Zeichen auf diese Beispiele.quelle
t
ista "b c
. Haben Sie ein Rezept haben diese 6 Zeichen für immer (a
2 × Raum,"
,b
, undc
) wie zu erscheinen%1
innerhalb einer.cmd
? Ich mag dein Denken.args "%t:"=""%"
ist ziemlich nah :-)Sie haben oben bereits einige gute Antworten, aber um einen Teil Ihrer Frage zu beantworten:
Was dort passiert ist, dass, weil Sie ein Leerzeichen vor dem = haben, eine Variable erstellt wird, die
%a<space>%
so genannt wird , wenn Sieecho %a %
korrekt ausgewertet werden alsb
.Der verbleibende Teil
b% c%
wird dann als einfacher Text + eine undefinierte Variable ausgewertet% c%
, die für michecho %a %b% c%
zurückgegeben werden solltebb% c%
Ich vermute, dass die Möglichkeit, Leerzeichen in Variablennamen aufzunehmen, eher ein Versehen als ein geplantes "Feature" ist.
quelle
Bearbeiten: Siehe akzeptierte Antwort. Das Folgende ist falsch und erklärt nur, wie eine Befehlszeile an TinyPerl übergeben wird.
In Bezug auf Zitate habe ich das Gefühl, dass das Verhalten wie folgt ist:
"
gefunden wird, beginnt das Globbing der Zeichenfolge"
ist, ist global"
gefunden wird:""
(also ein Dreifach"
), wird der Zeichenfolge ein doppeltes Anführungszeichen hinzugefügt"
(also ein Doppel"
), wird dem String ein doppeltes Anführungszeichen hinzugefügt und das Ende des String-Globbings"
Fall, endet das String-GlobbingZusamenfassend:
"a """ b "" c"""
besteht aus zwei Zeichenfolgen:a " b "
undc"
"a""
,"a"""
und"a""""
sind alle die gleiche Zeichenfolge, wenn am Ende einer Zeilequelle
Beachten Sie, dass Microsoft den Quellcode seines Terminals veröffentlicht hat. Es funktioniert möglicherweise ähnlich wie die Befehlszeile in Bezug auf die Syntaxanalyse. Vielleicht ist jemand daran interessiert, die rückentwickelten Parsing-Regeln gemäß den Parsing-Regeln des Terminals zu testen.
Link zum Quellcode.
quelle