
Ich versuche zu verstehen, wie die Zeichenfolgenersetzung in Windows-Batches tatsächlich funktioniert, und habe Probleme.
@echo off
set var=wild
set varnew=%var:l=n%
echo var is: %var%
echo varnew is: %varnew%
funktioniert; es erzeugt die erwartete Ausgabe:
var is: wild
varnew is: wind
Dies ist jedoch nicht der Fall (Beispielverzeichnis „Main“):
@echo off
for /D %%G IN (*) do (
setlocal
echo G is: %%G
set _srcp=%%G
echo _srcp is %_srcp%
rem set _newp=%_newp:ai=_01_% <-- confused variable
set _newp=%_srcp:ai=_01_%
echo._newp is: %_newp%
endlocal
)
Es wird folgende Ausgabe generiert:
G is: Main
_srcp is Main
_newp is: %_srcp:ai=_01_
Ich würde erwarten, dass der Code als letzte Zeile generiert wird _newp is: M_01_n
. Mir gehen hier wirklich die Ideen aus. Kann mir bitte jemand den richtigen Weg weisen?
BB
Antwort1
Sie haben ein paar Probleme:
%var%
Die Erweiterung erfolgt, wenn die Anweisung analysiert wird und der gesamte Codeblock in Klammern in einem Durchgang analysiert wird, bevor irgendwelche Befehle ausgeführt werden. Der Wert ist also der Wert, der vor dem Start der Schleife vorhanden war. Die Lösung ist eine verzögerte Erweiterung, die erfolgt, während jeder Befehl innerhalb der Schleife ausgeführt wird.Ihre Logik ist falsch - die Zuweisung von _newp sollte auf dem Wert von _srcp basieren
Der CMD-Prozessor ist ein kompliziertes Biest(und auch schlecht dokumentiert). Es gibt mehrere Punkte, an denen verschiedene Variablentypen erweitert werden, und Sie müssen diese vollständig verstehen, wenn Sie die Batch-Programmierung wirklich optimal nutzen möchten. Im Link wird alles erklärt, aber zusammengefasst ist die Reihenfolge der Erweiterung:
1) % Ausdehnung - Parameter:echo %1
oderUmgebungsvariable: echo %var%
---- Der Großteil der Analyse ist jetzt abgeschlossen ----
2) FOR-Variablenerweiterung: for %%A in (*) do echo %%A
3) Verzögerte Umgebungsvariablenerweiterung: echo !var!
4) CALL %-Erweiterung - Parameter:call echo %%1
oderUmgebungsvariable: call echo %%var%%
5) SET /A Umgebungsvariablenerweiterung: `set /a "value=var+1"
Beachten Sie, dass für die verzögerte Erweiterung die Aktivierung der verzögerten Erweiterung überSETLOCAL EnableDelayedExpansion
Der folgende Code mit verzögerter Erweiterung liefert das gewünschte Ergebnis:
@echo off
for /D %%G in (*) do (
setlocal enableDelayedExpansion
echo G is: %%G
set "_srcp=%%G"
echo _srcp is !_srcp!
set "_newp=!_srcp:ai=_01_!"
echo _newp is: !_newp!
endlocal
)
Beachten Sie, dass nach der FOR-Variablenerweiterung eine verzögerte Erweiterung erfolgt, sodass das Ergebnis beschädigt wird, wenn es %%G
constains enthält !
. Dies kann durch zusätzliches SETLOCAL vermieden werden:
for /D %%G in (*) do (
setlocal disableDelayedExpansion
echo G is: %%G
set "_srcp=%%G"
setlocal enableDelayedExpansion
echo _srcp is !_srcp!
set "_newp=!_srcp:ai=_01_!"
echo _newp is: !_newp!
endlocal
endlocal
)
Sie können das gewünschte Ergebnis auch mit CALL und doppelten Prozentwerten erzielen, aber das ist viel langsamer. Die Geschwindigkeit ist nicht wichtig, wenn es ein paar Mal ausgeführt wird, aber sie wird sehr wichtig, wenn es tausende Male in einer Schleife ausgeführt wird.
@echo off
for /D %%G in (*) do (
setlocal
echo G is: %%G
set "_srcp=%%G"
call echo _srcp is %%_srcp%%
call set "_newp=%%_srcp:ai=_01_%%"
call echo _newp is: %%_newp%%
endlocal
)
Antwort2
weiter zu davebenhams Antwort
echo %var% innerhalb eines Blocks wie FOR oder IF auszuführen, funktioniert nicht richtig. Die %var%-Variablen werden einfach nicht aktualisiert. Sie müssen !var! verwenden und damit !var! funktioniert, müssen Sie setlocal EnableDelayedExpansion verwenden.
eine Erklärung hierzu gibt es in der cmd-Hilfe, allerdings ist nicht klar, in welcher Befehlshilfe das erklärt wird! Es istset /?
set /?
Schließlich wurde Unterstützung für die verzögerte Erweiterung von Umgebungsvariablen hinzugefügt. Diese Unterstützung ist standardmäßig immer deaktiviert, kann aber über den Befehlszeilenschalter /V für CMD.EXE aktiviert/deaktiviert werden. Siehe CMD /?
Die verzögerte Erweiterung von Umgebungsvariablen ist nützlich, um die Einschränkungen der aktuellen Erweiterung zu umgehen, die beim Lesen einer Textzeile und nicht bei ihrer Ausführung auftritt. Das folgende Beispiel veranschaulicht das Problem der sofortigen Variablenerweiterung:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo If you see this, it worked )
würde die Meldung nie anzeigen, da %VAR% in BEIDEN IF-Anweisungen ersetzt wird, wenn die erste IF-Anweisung gelesen wird, da sie logischerweise den Hauptteil der IF-Anweisung enthält, die eine zusammengesetzte Anweisung ist. Das IF innerhalb der zusammengesetzten Anweisung vergleicht also tatsächlich „vorher“ mit „nachher“, was nie gleich sein wird. Ebenso wird das folgende Beispiel nicht wie erwartet funktionieren:
set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST%
indem KEINE Liste der Dateien im aktuellen Verzeichnis erstellt wird, sondern stattdessen nur die Variable LIST auf die letzte gefundene Datei gesetzt wird. Dies liegt wiederum daran, dass %LIST% nur einmal erweitert wird, wenn die FOR-Anweisung gelesen wird, und zu diesem Zeitpunkt ist die Variable LIST leer. Die eigentliche FOR-Schleife, die wir ausführen, ist also:
for %i in (*) do set LIST= %i
Dadurch wird LIST immer auf die zuletzt gefundene Datei gesetzt.
Die verzögerte Erweiterung von Umgebungsvariablen ermöglicht es Ihnen, ein anderes Zeichen (das Ausrufezeichen) zu verwenden, um Umgebungsvariablen zur Ausführungszeit zu erweitern. Wenn die verzögerte Variablenerweiterung aktiviert ist, könnten die obigen Beispiele wie folgt geschrieben werden, um wie vorgesehen zu funktionieren:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "!VAR!" == "after" @echo If you see this, it worked ) set LIST= for %i in (*) do set LIST=!LIST! %i echo %LIST%
Sie können die Notation auch von der Kommandozeile aus testen mit
cmd /e:on
beginnend mit der Standardeinstellung cmd /v:off und dann weiter zu cmd/v:on. Die meisten verwenden cmd .v:off, sogar Experten (vielleicht, weil andere Dinge damit anders interpretiert werden können), daher verwende ich dies nur, um Ihnen zu zeigen, dass Sie damit die !var!-Notation innerhalb von cmd ausprobieren können.
C:\>set a=5
C:\>echo %a%
5
C:\>echo !a!
!a!
C:\>cmd /v:on
Microsoft Wind
Copyright (c)
C:\>echo !a!
5
C:\>
Übrigens, wenn Sie cmd /v:on oder in einer Batchdatei EnableDelayedExpansion aktiviert hätten, müssten Sie, wie Dave zeigt, wissen, dass ! ein Sonderzeichen ist, sodass Sie ein Problem hätten, wenn das ! innerhalb eines %var% stünde. Das wäre also ein Grund, warum die Leute den Modus nicht einfach dauerhaft einschalten, es kann auch andere Gründe geben.