¿Por qué no es necesario escapar de los signos de exclamación en el parámetro `for / F` o` for / R`?
Cuandoexpansión demorada está habilitado, es (generalmente) necesario escapar de los signos de exclamación correctamente para obtener los literales (como^^!
o, al estar en el medio""
, ^!
, para obtener un literal!
)
Sin embargo, ¿por qué no es necesario escapar de los signos de exclamación, sino incluso destructivos dentro de los parámetros proporcionados inmediatamente después del/R
o la/F
interruptor de lafor
comando de bucle?
Con las reglas de escape antes mencionadas en mente, creé el siguiente script por lotes usandofor /R
y como parámetro un directorio con un!
en su nombre (indicado después del/R
opción):
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "TARGET=excl^!dir"
set "FILE=empty_%RANDOM%.txt"
echo/
echo creating directory: !TARGET!
mkdir "!TARGET!"
echo placing empty file: !TARGET!\%FILE%
> "!TARGET!\%FILE%" break
echo/
echo adequately escaped `^^!`:
for /R "excl^!dir" %%F in ("*.*") do echo(found item: %%~nxF
for /R excl^^!dir %%F in ("*.*") do echo(found item: %%~nxF
echo/
echo improperly escaped `^^!`:
for /R "excl!dir" %%F in ("*.*") do echo(found item: %%~nxF
for /R excl!dir %%F in ("*.*") do echo(found item: %%~nxF
for /R excl^!dir %%F in ("*.*") do echo(found item: %%~nxF
erase "!TARGET!\%FILE%"
rmdir "!TARGET!"
endlocal
exit /B
Sorprendentemente, el directorio solo se enumerasin escapando del!
. Esta es una salida:
creating directory: excl!dir
placing empty file: excl!dir\empty_18378.txt
adequately escaped `!`:
improperly escaped `!`:
found item: empty_18378.txt
found item: empty_18378.txt
found item: empty_18378.txt
Espero que el directorio se enumere en caso de que el signo de exclamaciónes de hecho escapó adecuadamente, de lo contrario no; pero el resultado muestra el comportamiento opuesto.
Un fenómeno similar surge confor /F
, como en el siguiente script con un!
en la cadena de opciones:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "STRING=EXCLAMATION ^! MARK AND CARET ^^ SYMBOL"
echo/
echo normal expansion: %STRING%
echo delayed expansion: !STRING!
echo/
echo adequately escaped `^^!`:
for /F "tokens=1-2 delims=^!" %%K in ("!STRING!") do echo(%%K -- %%L
for /F tokens^=1-2^ delims^=^^! %%K in ("!STRING!") do echo(%%K -- %%L
echo/
echo improperly escaped `^^!`:
for /F "tokens=1-2 delims=!" %%K in ("!STRING!") do echo(%%K -- %%L
for /F tokens^=1-2^ delims^=! %%K in ("!STRING!") do echo(%%K -- %%L
for /F tokens^=1-2^ delims^=^! %%K in ("!STRING!") do echo(%%K -- %%L
endlocal
exit /B
La salida se ve así, extrañamente:
normal expansion: EXCLAMATION MARK AND CARET SYMBOL
delayed expansion: EXCLAMATION ! MARK AND CARET ^ SYMBOL
adequately escaped `!`:
EXCLAMATION -- MARK AND CARET
EXCLAMATION -- MARK AND CARET
improperly escaped `!`:
EXCLAMATION -- MARK AND CARET ^ SYMBOL
EXCLAMATION -- MARK AND CARET ^ SYMBOL
EXCLAMATION -- MARK AND CARET ^ SYMBOL
Aquí espero que toda la cadena se divida en exactamente dos tokens:EXCLAMATION
yMARK AND CARET ^ SYMBOL
. Pero la segunda ficha es demasiado corta, todo comienza con el símbolo de intercalación.^
Está perdido; así que concluyo que el^
utilizado para escapar de la!
se toma literalmente Sin escape (o pobre), los tokens devueltos son los deseados.