Wie funktioniert die verzögerte Erweiterung in einem Batch-Skript?

Wie funktioniert die verzögerte Erweiterung in einem Batch-Skript?

Nehmen Sie diese einfache Reihe von Befehlen, die in einer Batchumgebung ausgeführt werden:

>set ar[0]=orange
>set ar[1]=apple
>set ar[2]=banana
>for %i in (0,1,2) do echo !ar[%i]!

Es gibt Folgendes aus:

>echo !ar[0]!
!ar[0]!
>!ar[1]!
!ar[1]!
>!ar[2]!
!ar[2]!

Es wird also offensichtlich nicht auf seine Werte erweitert. Wie würde ich das tun?

Antwort1

Quellen:
Phase 5InWie analysiert der Windows-Befehlsinterpreter (CMD.EXE) Skripts?

Verzögerte Erweiterung:Nur wenn die verzögerte Erweiterung eingeschaltet ist, befindet sich der Befehl nicht in einemeingeklammerter Block auf beiden Seiten eines Rohrsund der Befehl ist kein"nacktes" Batch-Skript(Skriptname ohne Klammern, CALL, Befehlsverkettung oder Pipe).

  • Jedes Token für einen Befehl wird unabhängig auf 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 Token der IN-Klausel.
    • Der IF-Befehl analysiert nur die Vergleichswerte – entweder einen oder zwei, abhängig vom Vergleichsoperator.
  • Überprüfen Sie für jedes analysierte Token zunächst, ob es ein enthält !. Wenn nicht, wird das Token nicht analysiert – wichtig für ^Zeichen. Wenn das Token ein enthält !, scannen Sie jedes Zeichen von links nach rechts:
    • Handelt es sich um ein Caretzeichen ( ^), hat das nächste Zeichen keine besondere Bedeutung, das Caretzeichen selbst wird entfernt
    • Wenn es ein Ausrufezeichen ist, suchen Sie nach dem nächsten Ausrufezeichen (Caretzeichen werden nicht mehr beachtet) und erweitern Sie es auf den Wert der Variablen.
      • Aufeinanderfolgende Öffnungen !werden zu einer einzigen zusammengefasst!
      • Alle verbleibenden !ungepaarten
    • Das Erweitern von Variablen in dieser Phase ist „sicher“, da Sonderzeichen nicht mehr erkannt werden (auch nicht <CR>oder <LF>).
    • Für eine ausführlichere Erklärung lesen Sie die 2. Hälfte von dbenham gleicher Thread - Ausrufezeichenphase

Phase 5.3) Rohrbearbeitung:Nur wenn sich Befehle auf beiden Seiten einer Pipe befinden.
Jede Seite der Pipe wird unabhängig und asynchron verarbeitet.

  • Wenn der Befehl intern in cmd.exe ist oder es sich um eine Batchdatei handelt oder wenn es sich um einen in Klammern gesetzten Befehlsblock handelt, wird er in einem neuen cmd.exe-Thread über ausgeführt %comspec% /S /D /c" commandBlock", sodass der Befehlsblock einen Phasenneustart erhält, dieses Mal jedoch im Befehlszeilenmodus.
    • Wenn es sich um einen eingeklammerten Befehlsblock handelt, <LF>werden alle mit einem Befehl davor und danach in umgewandelt <space>&. Die anderen <LF>werden entfernt.
  • Dies ist das Ende der Verarbeitung der Pipe-Befehle.
  • Sehenhttps://stackoverflow.com/q/8192318/1012053für mehr Informationen zur Pipe-Analyse und -Verarbeitung

Phase 5.5) Umleitung ausführen:Alle in Phase 2 erkannten Umleitungen werden jetzt ausgeführt.



Bildbeschreibung hier eingeben

  • Sie können auch dieDelayed Expansionvoncmd.exemit Flagge[/v:on | /v], auf deroder im/Dateien.

Bildbeschreibung hier eingeben

set ar[0]=orange
set ar[1]=apple
set ar[2]=banana
for %i in (0,1,2) do cmd.exe /v:on /C"echo !ar[%i]!

  • In deinem/Datei ohne Angabesetlocal enabledelayedexpansionkönnen Sie auchcmd.exe /v:on /c "command & command | command || command..."
@echo off 

set "ar[0]=orange" 
set "ar[1]=apple"
set "ar[2]=banana" 
for %%i in (0,1,2)do cmd /v /c "echo\ !ar[%%i]!"

  • In deinem/erklärtsetlocal enabledelayedexpansion:
@echo off 

set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana" 

setlocal enabledelayedexpansion
for %%i in (0,1,2)do echo\ !ar[%%i]!

enndlocal


@echo off 
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana" 
for %%i in (0,1,2)do %ComSpec% /v:on /c"echo !ar[%%i]!"
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off 
set "ar[0]=orange" & set "ar[1]=apple" & set "ar[2]=banana" 
setlocal enabledelayedexpansion && for %%i in (0,1,2)do echo\ !ar[%%i]!
%__APPDIR__%timeout.exe /t -1 & endlocal & goto :EOF
@echo off 
set "ar[0]=orange" && set "ar[1]=apple" && set "ar[2]=banana" 
for %%i in (0,1,2)do <con: %ComSpec% /v:on /c"echo !ar[%%i]!"
call <con: rem./ && %__APPDIR__%timeout.exe /t -1 && endlocal
  • Sie können auchcallIn/oder in Ihrer Befehlszeile, um diesen Wert zu aktualisieren:
set "ar[0]=orange"
set "ar[1]=apple"
set "ar[2]=banana" 
for %i in (0,1,2)do for %i in (0,1,2)do <con: call echo %ar[%i]%


  • In deinem/Datei oder Befehlszeile, alle folgenden Befehle sind gleich, wobei das Ersetzen zu beachten ist%imit%%ibei Verwendung in/Dateien
for %i in (0,1,2) do %ComSpec% /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v:on /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v:on /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd /v:on /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v:on /c "echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec% /v /r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec% /v /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe /v /c "echo !ar[%i]!"

for %i in (0,1,2) do cmd /v /r "echo !ar[%i]!"
for %i in (0,1,2) do cmd /v /c "echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd/v:on/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c "echo !ar[%i]!"

for %i in (0,1,2) do %ComSpec%/v/r "echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c "echo !ar[%i]!"

for %i in (0,1,2) do cmd/v/r "echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c "echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v:on/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v:on/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd/v:on/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v:on/c"echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v/r"echo !ar[%i]!"
for %i in (0,1,2) do %ComSpec%/v/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!"

for %i in (0,1,2) do cmd/v/r"echo !ar[%i]!"
for %i in (0,1,2) do cmd/v/c"echo !ar[%i]!"


for %i in (0,1,2) do %ComSpec%/v/recho !ar[%i]!
for %i in (0,1,2) do %ComSpec%/v/cecho !ar[%i]!

for %i in (0,1,2) do cmd.exe/v/r"echo !ar[%i]!
for %i in (0,1,2) do cmd.exe/v/c"echo !ar[%i]!

for %i in (0,1,2) do cmd/v/recho !ar[%i]!
for %i in (0,1,2) do cmd/v/cecho !ar[%i]!

Antwort2

Die verzögerte Erweiterung wird hauptsächlich verwendet, um Variablenwerte mehr als einmal zu erweitern, insbesondere in For-Schleifen.

Zitat aushttps://ss64.com/nt/delayedexpansion.html

Die verzögerte Erweiterung führt dazu, dass Variablen in einer Batchdatei zum Ausführungszeitpunkt und nicht zum Analysezeitpunkt erweitert werden. Diese Option wird mit dem Befehl SETLOCAL EnableDelayedExpansion aktiviert.

Variablenerweiterung bedeutet das Ersetzen einer Variable (z. B. %windir%) durch ihren Wert C:\WINDOWS

Standardmäßig wird die Erweiterung nur einmal durchgeführt, und zwar vor der Ausführung jeder Zeile. Die !delayed!-Erweiterung wird bei jeder Ausführung der Zeile oder bei jeder Schleife in einem FOR-Schleifenbefehl durchgeführt. Sehen wir uns zunächst dieses Beispiel an:

set i=0
for /l %%a in (0,1,10) do (
  set /a i=%i%+1
  echo %i%
)

Hier erwarten wir, dass die Zahlen 1 bis 10 ausgegeben werden. Es wird jedoch jedes Mal nur 0 ausgegeben. Da die Variablen jedes Mal einmal erweitert werden, ändern sich die Werte nicht.

Dieses Mal versuchen wir es mit verzögerter Erweiterung:

setlocal enabledelayedexpansion 
set i=0
for /l %%a in (0,1,10) do (
  set /a i=!i!+1
  echo !i!
)

Dieses Mal erhalten wir die erwartete Ausgabe, da sich der Wert jedes Mal ändert, wenn wir die Werte erweitern.

Ihr Code funktioniert nicht, weil Sie setlocal enabledelayedexpansionam Anfang Ihres Codes hinzufügen müssen.

Ich hoffe, das hilft

verwandte Informationen