Tome esta sencilla serie de comandos ejecutados en un entorno por lotes:
>set ar[0]=orange
>set ar[1]=apple
>set ar[2]=banana
>for %i in (0,1,2) do echo !ar[%i]!
Produce lo siguiente:
>echo !ar[0]!
!ar[0]!
>!ar[1]!
!ar[1]!
>!ar[2]!
!ar[2]!
Por lo tanto, obviamente no se expande a sus valores. ¿Cómo lo haría?
Respuesta1
Fuentes:
Fase 5en¿Cómo analiza los scripts el intérprete de comandos de Windows (CMD.EXE)?
Expansión retrasada:Sólo si la expansión retardada está activada, el comando no está en unabloque entre paréntesis a cada lado de una tubería, y el comando no es unscript por lotes "desnudo"(nombre del script sin paréntesis, CALL, concatenación de comandos o canalización).
- Cada token de un comando se analiza de forma independiente para determinar la expansión retrasada.
- La mayoría de los comandos analizan dos o más tokens: el token de comando, el token de argumentos y cada token de destino de redirección.
- El comando FOR analiza únicamente el token de la cláusula IN.
- El comando IF analiza solo los valores de comparación, uno o dos, según el operador de comparación.
- Para cada token analizado, primero verifique si contiene algún archivo
!
. De lo contrario, el token no se analiza, lo cual es importante para^
los personajes. Si el token contiene!
, escanee cada carácter de izquierda a derecha:- Si es un símbolo de intercalación (
^
), el siguiente carácter no tiene ningún significado especial, el símbolo de intercalación en sí se elimina. - Si es un signo de exclamación, busque el siguiente signo de exclamación (ya no se observan signos de intercalación), expanda al valor de la variable.
- Las aperturas consecutivas
!
se colapsan en una sola!
- Cualquier resto no emparejado
!
se elimina
- Las aperturas consecutivas
- Expandir vars en esta etapa es "seguro", porque ya no se detectan caracteres especiales (incluso
<CR>
o<LF>
) - Para una explicación más completa, lea la segunda mitad de esto de dbenham. mismo hilo - Fase de signo de exclamación
- Si es un símbolo de intercalación (
Fase 5.3) Procesamiento de tuberías:Solo si los comandos están en cualquier lado de una tubería.
Cada lado de la tubería se procesa de forma independiente y asincrónica.
- Si el comando es interno de cmd.exe, o es un archivo por lotes, o si es un bloque de comando entre paréntesis, entonces se ejecuta en un nuevo hilo de cmd.exe a través de
%comspec% /S /D /c" commandBlock"
, por lo que el bloque de comando se reinicia por fase, pero esta vez en modo de línea de comando.- Si es un bloque de comando entre paréntesis, todos los
<LF>
que tengan un comando antes y después se convierten a<space>&
. Otros<LF>
están despojados.
- Si es un bloque de comando entre paréntesis, todos los
- Este es el final del procesamiento de los comandos de canalización.
- Verhttps://stackoverflow.com/q/8192318/1012053para más información sobre el análisis y procesamiento de tuberías
Fase 5.5) Ejecutar Redirección:Cualquier redirección que se haya descubierto en la fase 2 ahora se ejecuta.
- Los resultados de las fases 4 y 5 pueden afectar la redirección que se descubrió en la fase 2.
- Si la redirección falla, se cancela el resto del comando.Tenga en cuenta que la redirección fallida no establece ERRORLEVEL en 1 a menos que
||
se utilice.
- También puedes utilizar el
Delayed Expansion
porcmd.exe
con bandera[/v:on | /v]
, sobre ellínea de comandoo en elmurciélago/cmdarchivos.
- En tuslínea de comandousando
cmd.exe /v:on /c
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]!
- En tusmurciélago/cmdpresentar sin declarar
setlocal enabledelayedexpansion
, también puedes usarcmd.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]!"
- En tusmurciélago/cmddeclarando
setlocal 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
- Algunas variaciones de diseño para estomurciélago/cmdcódigo:
@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
- También puedes usar
call
enmurciélago/cmdo en su línea de comando para actualizar este valor:
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]%
- En tusmurciélago/cmdarchivo o línea de comando, todos los siguientes comandos son iguales, observando el reemplazo
%i
con%%i
en el caso de uso enmurciélago/cmdarchivos
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]!
Algunas lecturas adicionales:
[√]colocar /?
[√]CMD /?
[√]En bucle
[√]Ejecución condicional || &&...
[√]¿Por qué el conjunto de llamadas funciona de manera diferente?
[√]Comprensión de inicio, 2>nul, cmd y otros símbolos en un archivo por lotes
[√]Utilice paréntesis/corchetes para agrupar expresiones en un archivo por lotes de Windows
Respuesta2
La expansión retardada se utiliza principalmente para expandir valores de variables más de una vez, especialmente en bucles For.
Citando dehttps://ss64.com/nt/delayedexpansion.html
La expansión retrasada hará que las variables dentro de un archivo por lotes se expandan en el momento de la ejecución en lugar de en el momento del análisis; esta opción se activa con el comando SETLOCAL EnableDelayedExpansion.
La expansión de variables significa reemplazar una variable (por ejemplo, %windir%) con su valor C:\WINDOWS
De forma predeterminada, la expansión se producirá solo una vez, antes de que se ejecute cada línea. El !retrasado! la expansión se realiza cada vez que se ejecuta la línea, o para cada bucle en un comando de bucle FOR. Primero miramos este ejemplo:
set i=0
for /l %%a in (0,1,10) do (
set /a i=%i%+1
echo %i%
)
Aquí esperamos que esto genere los números del 1 al 10. Sin embargo, cada vez generará solo 0. Debido a que cada vez que las variables se expanden una vez, los valores no cambian.
Esta vez intentaremos con la expansión retrasada:
setlocal enabledelayedexpansion
set i=0
for /l %%a in (0,1,10) do (
set /a i=!i!+1
echo !i!
)
Esta vez obtendremos el resultado esperado, porque cada vez que expandimos los valores, el valor cambia.
Su código no funciona porque debe agregarlo setlocal enabledelayedexpansion
al inicio de su código.
Espero que ayude