Почему в параметре "for /F" или "for /R" нет необходимости избегать восклицательных знаков?

, когда отложенная экспансия включено, (обычно) необходимо правильно избегать восклицательных знаков, чтобы получить буквальные (например,^^! или, находясь между "", ^!, чтобы получить буквальное !).

, почему не избежать восклицательных знаков обязательно, но даже в деструктивных параметров сразу после /R или /F переключатель for петли команда?

имея в виду вышеупомянутые правила экранирования, я создал следующий пакетный скрипт, используя for /R и в качестве параметра каталог с ! в его названии (указано после ):

@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

удивительно, каталог перечисляется только без побег !. Это вывод:

creating directory: excl!dir
placing empty file: excl!dirempty_18378.txt

adequately escaped `!`:

improperly escaped `!`:
found item: empty_18378.txt
found item: empty_18378.txt
found item: empty_18378.txt

я ожидаю, что каталог будет перечислен в случае восклицательного знака is на самом деле правильно убежал, иначе нет; но результат показывает противоположное поведение.


подобное явление возникает с for /F, как в следующем сценарии с ! в строке вариант:

@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

выход выглядит так, странно:

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

здесь я ожидаю, что вся строка будет разделена ровно на два токена:EXCLAMATION и MARK AND CARET ^ SYMBOL. Но второй токен слишком короткий, все, начиная с символа каретки ^ отсутствует; поэтому я заключаю, что ^ используется для побега ! это воспринимать буквально. При отсутствии (или плохом) побеге возвращенные маркеры являются предполагаемыми.

1 ответов


варианты FOR, IF и REM анализируются только до специальной фазы символов.
Или лучше команды обнаруживаются в специальной фазе символов, и тогда активируется другой парсер.

поэтому в опциях невозможно использовать отложенное расширение или параметр FOR.

тесты с ошибками

for /F %%O in ("defined") do (
  if %%O var echo yes
)

set option=defined
if !option! var echo yes

это, кажется, работает, но использует неправильные разделители (D, e, i, l, m, s, y и ! )

set "myDelims=123"
for /F "tokens=1,2 delims=!myDelims!" %%A in ("Hello 1 world") do (
    echo Token1=%%A  Token2=%%B
)

и для REM

set "help=/?"
REM !HELP!  - No help will be shown