为什么FOR在IN之后延迟子串扩展失败?

时间:2018-05-16 21:47:12

标签: batch-file for-loop cmd delayedvariableexpansion

当使用立即扩展时,子字符串扩展在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

1 个答案:

答案 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存在一个非常类似的问题。)