Ejemplo de expansión retrasada en un archivo por lotes

Resuelto Neil Weicher asked hace 12 años • 5 respuestas

¿Alguien puede darme un ejemplo de dónde un script por lotes actuaría de manera diferente con o sin expansión retrasada? ¿Existe alguna situación en la que NO desee utilizar la expansión retrasada? Gracias.

Neil Weicher avatar May 12 '12 03:05 Neil Weicher
Aceptado

Mira los siguientes ejemplos...

Ejemplo 1: el siguiente código NO utiliza expansión retrasada, por lo que las variables en el bucle for se expanden solo una vez. Esto significa que %Count%siempre se expandirá 0en cada iteración del bucle, sin importar lo que le hagamos con el comando set:

@echo off
set COUNT=0

for %%v in (1 2 3 4) do (
  set /A COUNT=%COUNT% + 1
  echo Count = %COUNT%
)
pause

Entonces este script generará:

Count = 0
Count = 0
Count = 0
Count = 0

No es así como se supone que funciona este bucle.

Ejemplo 2: Por otro lado, si usamos expansión retrasada, tenemos el siguiente script, que se ejecutará como se esperaba.

setlocal ENABLEDELAYEDEXPANSION
set COUNT=0

for %%v in (1 2 3 4) do (
  set /A COUNT=!COUNT! + 1
  echo Count = !COUNT!
)

pause

y, como se esperaba, generará:

Count = 1
Count = 2
Count = 3
Count = 4

Cuando usa ENABLEDELAYEDEXPANSIONy expande una variable usando !en lugar de %, la variable se vuelve a expandir cada vez y todo funciona como se supone que debe hacerlo.

Max avatar May 11 '2012 21:05 Max

Quería agregar un gran ejemplo sobre cómo "EnableDelayedExpansion" (EDE) puede ser útil fuera de los omnipresentes ejemplos de bucle FOR.

Aquí hay una línea de datos de terremotos que deseo analizar (la llamo 1line.txt)

ak_11574812 2015.04.29.193822 62.9525 -148.8849 1.0 9.5 1 49 km al sur de Cantwell, Alaska

El problema con el que me encontré fue que el último segmento de esta línea no siempre comienza en el mismo número de columna. Entonces necesitaba crear un comando SET flexible que arrancara con precisión el último segmento de esta línea.

ECHO OFF
setlocal enableDelayedExpansion
set where=72
set /p line=<1line.txt
set locate=!line:~%where%,28!
echo %locate%

EDE me permite colocar una variable (dónde) dentro de otra variable (línea). EDE traducirá primero la variable entre corchetes % y luego procesará la variable entre corchetes ! y (en este caso) enviar los resultados a la variable "localizar".

Bruce Sinkula avatar Apr 30 '2015 19:04 Bruce Sinkula

La respuesta de Max da un ejemplo de dónde un script por lotes actuaría de manera diferente con o sin expansión retrasada .

Para completar, respondamos otra parte de la pregunta y mostremos una situación en la que NO desearía utilizar la expansión retrasada cuando sus datos contienen un signo de exclamación !(y mostraremos dos formas de procesar dichos datos):

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion

  set "_auxFile=%temp%\%~n0.txt"
  rem create multiline sample file
  >"%_auxFile%" ( for /L %%G in (1,1,3) do echo line %%G is 100%% valid! Sure! Hurrah!)
  rem create one-line sample file
  >"%_auxFile%" echo this line is 100%% valid! Sure! Hurrah!

  echo(
  echo --- file content 
  type "%_auxFile%"

  echo(
  SETLOCAL EnableDelayedExpansion
    echo --- enabled delayed expansion chokes down unescaped exclamation marks^^^! "^!"
    for /F "usebackq delims=" %%G in ("%_auxFile%") do (
      set "_auxLine=%%~G"
      echo loop var=%%~G
      echo _auxLine=!_auxLine!
    )
  ENDLOCAL
  echo(
  SETLOCAL DisableDelayedExpansion
    echo --- toggled delayed expansion works although might be laborious!
    for /F "usebackq delims=" %%G in ("%_auxFile%") do (
      set "_auxLine=%%G"
      echo loop var=%%G
      SETLOCAL EnableDelayedExpansion
        echo _auxLine=!_auxLine!
      ENDLOCAL
    )
  ENDLOCAL
  echo(
  SETLOCAL DisableDelayedExpansion
    echo --- keep delayed expansion DISABLED: use CALL command!
    for /F "usebackq delims=" %%G in ("%_auxFile%") do (
      set "_auxLine=%%G"
      echo loop var=%%G
      call :ProcessVar
    )
  ENDLOCAL

  rem delete the sample file
  del "%_auxFile%"
ENDLOCAL
goto :eof

:ProcessVar
  echo _auxLine=%_auxLine%
  echo WARNING: neither !_auxLine! nor %%G loop variable is available here!  
goto :eof

Tenga en cuenta que el script anterior muestra formas adecuadas de escapar

  • %signo de porcentaje %%duplicándolo (la expansión retrasada no importa), y
  • !signo de exclamación si la expansión retrasada está habilitada:
    • "^!"si está entre comillas dobles, utilice el cmdcarácter de intercalación de escape general del script por lotes y ^;
    • ^^^!de lo contrario, utilice tres ^signos de intercalación.

Producción :

==> D:\bat\SO\10558316.bat

--- file content
this line is 100% valid! Sure! Hurrah!

--- enabled delayed expansion chokes down unescaped exclamation marks! "!"
loop var=this line is 100% valid Hurrah
_auxLine=this line is 100% valid Hurrah

--- toggled delayed expansion works although might be laborious!
loop var=this line is 100% valid! Sure! Hurrah!
_auxLine=this line is 100% valid! Sure! Hurrah!

--- keep delayed expansion DISABLED: use CALL command!
loop var=this line is 100% valid! Sure! Hurrah!
_auxLine=this line is 100% valid! Sure! Hurrah!
WARNING: !_auxLine! as well as %G loop variables are not available here!

==>
JosefZ avatar Jun 25 '2016 10:06 JosefZ