
Estoy tratando de entender cómo funciona realmente el reemplazo de cadenas en lotes de Windows y tengo problemas.
@echo off
set var=wild
set varnew=%var:l=n%
echo var is: %var%
echo varnew is: %varnew%
funciona; genera el resultado esperado:
var is: wild
varnew is: wind
Pero esto no es así (ejemplo de directorio "Principal"):
@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
)
Genera esta salida:
G is: Main
_srcp is Main
_newp is: %_srcp:ai=_01_
Esperaría que el código se generara _newp is: M_01_n
como última línea. Realmente no tengo ideas aquí, ¿alguien puede indicarme la dirección correcta?
CAMA Y DESAYUNO
Respuesta1
Tienes un par de problemas:
%var%
La expansión ocurre cuando se analiza la declaración y todo el bloque de código entre paréntesis se analiza de una sola vez, antes de ejecutar cualquier comando. Entonces el valor es el valor que existía antes de que se iniciara el ciclo. La solución es la expansión retrasada, que ocurre cuando se ejecuta cada comando dentro del bucle.Su lógica es incorrecta: la asignación de _newp debe basarse en el valor de _srcp
El procesador CMD es una bestia complicada(y también mal documentado). Hay varios puntos en los que se amplían varios tipos de variables y debe comprenderlos completamente si realmente desea aprovechar al máximo la programación por lotes. Está todo explicado en el enlace, pero a modo de resumen, el orden de ampliación es:
1) % de expansión - Parámetro:echo %1
oVariable de entorno: echo %var%
---- La mayor parte del análisis ya se ha completado ----
2) PARA la expansión de la variable: for %%A in (*) do echo %%A
3) Expansión de la variable de entorno retrasada: echo !var!
4) CALL % de expansión - Parámetro:call echo %%1
oVariable de entorno: call echo %%var%%
5) SET /A expansión de variable de entorno: `set /a "valor=var+1"
Tenga en cuenta que la expansión retrasada requiere que la expansión retrasada esté habilitada a través deSETLOCAL EnableDelayedExpansion
El siguiente código que utiliza expansión retrasada le dará el resultado que busca:
@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
)
Tenga en cuenta que la expansión retrasada se produce después de la expansión de la variable FOR, por lo que el resultado se corromperá si %%G
consta !
. Esto se puede evitar mediante SETLOCAL adicional:
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
)
También podría obtener el resultado deseado usando CALL con porcentajes dobles, pero esto es mucho más lento. La velocidad no es importante si se ejecuta varias veces, pero se vuelve muy significativa si se ejecuta miles de veces en un bucle.
@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
)
Respuesta2
además de la respuesta de Davebenham
hacer echo %var% dentro de un bloque como FOR o IF no funciona correctamente. Las variables %var% simplemente no se actualizan. Tienes que usar !var! y para obtener !var! para funcionar tienes que configurar local EnableDelayedExpansion
Existe una explicación de esto en la ayuda de cmd, ¡aunque no es obvio qué ayuda del comando lo explica! Esset /?
set /?
Finalmente, se ha agregado soporte para la expansión retrasada de variables de entorno. Este soporte siempre está deshabilitado de forma predeterminada, pero se puede habilitar/deshabilitar mediante el cambio de línea de comando /V a CMD.EXE. Ver CMD /?
La expansión retardada de la variable de entorno es útil para sortear las limitaciones de la expansión actual que ocurre cuando se lee una línea de texto, no cuando se ejecuta. El siguiente ejemplo demuestra el problema con la expansión variable inmediata:
set VAR=before if "%VAR%" == "before" ( set VAR=after if "%VAR%" == "after" @echo If you see this, it worked )
nunca mostraría el mensaje, ya que el %VAR% en AMBAS declaraciones IF se sustituye cuando se lee la primera declaración IF, ya que lógicamente incluye el cuerpo de la declaración IF, que es una declaración compuesta. Entonces, el SI dentro de la declaración compuesta realmente compara "antes" con "después", que nunca serán iguales. De manera similar, el siguiente ejemplo no funcionará como se esperaba:
set LIST= for %i in (*) do set LIST=%LIST% %i echo %LIST%
en el sentido de que NO creará una lista de archivos en el directorio actual, sino que simplemente establecerá la variable LIST en el último archivo encontrado. Nuevamente, esto se debe a que %LIST% se expande solo una vez cuando se lee la instrucción FOR y en ese momento la variable LIST está vacía. Entonces el bucle FOR real que estamos ejecutando es:
for %i in (*) do set LIST= %i
que sigue configurando LIST en el último archivo encontrado.
La expansión retrasada de las variables de entorno le permite utilizar un carácter diferente (el signo de exclamación) para expandir las variables de entorno en el momento de la ejecución. Si la expansión variable retardada está habilitada, los ejemplos anteriores podrían escribirse de la siguiente manera para que funcionen según lo previsto:
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%
También puedes probar la notación desde la línea de comando con
cmd /e:on
comenzando con el valor predeterminado, cmd /v:off y luego pasando a cmd/v:on La mayoría usa cmd .v:off incluso los expertos (tal vez porque otras cosas se pueden interpretar de manera diferente), así que solo estoy usando esto para mostrar usted que puede probar el !var! notación dentro de cmd con él.
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:\>
Por cierto, si tenía cmd /v: activado o en un archivo por lotes, EnableDelayedExpansion activado, entonces, como muestra Dave, ¡debería tenerlo en cuenta! al ser un personaje especial, tendrías un problema si ! estaba dentro de un %var%. Entonces esa sería una razón por la cual la gente no activa el modo a tiempo completo, puede haber otras razones.