当使用立即扩展时,子字符串扩展在for
循环(即in
之后的括号部分)的集合内工作(写%%I
而不是{{1} }在批处理文件中):
%I
但是,当应用延迟扩展时,它会失败:
set "X=123"
for %I in (%X:~1,1%) do @echo %I
我希望输出为:
for %I in (!X:~1,1!) do @echo %I
但它是:
2
为什么会这样,我该如何预防呢?
我知道我可以通过引用该集并使用!X:~1
1!
来解决这个问题,但这不是我想要的:
~
以下命令行也会失败:
for %I in ("!X:~1,1!") do @echo %~I
意外的输出是:
for %I in (!X:*2=!) do @echo %I
使用!
,for
和/R
开关的/L
命令行也会因这种子字符串语法而失败。
这肯定与/R
和,
是=
的标记分隔符这一事实有关,就像 SPACE , TAB一样,cmd
等
答案 0 :(得分:0)
根据帖子How does the Windows Command Interpreter (CMD.EXE) parse scripts?以及此处的numerous comments,答案在于解析for
循环的特殊方式。
关键是以下this answer的摘录(特别参见斜体文字):
阶段2)处理特殊字符,标记化并构建缓存的命令块:
[...]
- 三个命令得到特殊处理 - IF,FOR和REM
[...]
- 在DO之后将FOR分成两部分。 FOR构造中的语法错误将导致致命的语法错误。
- 通过DO的部分是实际的FOR迭代命令,它一直流过第7阶段
- 在第2阶段完全解析所有FOR选项。
- IN括号内的子句将
<LF>
视为<space>
。解析IN子句后,所有标记将连接在一起形成一个标记。- 连续的令牌分隔符通过DO在整个FOR命令中折叠到一个空格中。
由于在解析for
和描述的行为之后发生了延迟扩展,因此令牌分隔符如 SPACE , TAB ,,
,;
,=
等转换为单个 SPACE ,因此像!X:~1,1!
这样的子字符串扩展表达式更改为!X:~1 1!
,像!X:*2=!
这样的子字符串替换表达式更改为!X:*2 !
,这两者都是无效的语法。
因此,要解决此问题,您需要通过^
转义令牌分隔符,如:
for %I in (!X:~1^,1!) do @echo %I
和
for %I in (!X:*2^=!) do @echo %I
(顺便说一句,if
statements存在一个非常类似的问题。)