为什么在' for /F '或' for /R '参数中不需要转义感叹号?



当启用延迟扩展时,(通常)需要正确转义感叹号以获得文字(例如^^!,或者当位于"", ^!之间时,为了获得文字!)。

但是,为什么在紧接for循环命令的/R/F开关后提供的参数中不需要转义感叹号,甚至是破坏性的?


考虑到前面提到的转义规则,我使用for /R创建了以下批处理脚本,并将名称中包含!的目录作为参数(在/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

我希望在感叹号实际上被正确转义的情况下枚举目录,否则没有;但结果显示相反的行为。


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

这里我希望整个字符串被分割成两个令牌:EXCLAMATIONMARK AND CARET ^ SYMBOL。但是第二个标记太短了,从插入符号^开始的所有内容都缺失了;因此,我得出的结论是,用于转义!^是从字面上理解的。如果没有(或没有)转义,返回的标记就是预期的标记。

FORIFREM的选项只被解析到特殊字符阶段。
或者更好的情况是,在特殊字符阶段检测命令,然后激活不同的解析器。

因此不可能在选项中使用延迟展开或FOR-Parameter。

这些测试失败,并出现错误

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

相关内容

最新更新