¿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.

Respuestas a la pregunta(1)

Su respuesta a la pregunta