for-loop和delimiters

时间:2013-06-30 13:37:00

标签: windows for-loop batch-file cmd

我需要快速的方法在bat文件中插入几行结构化数据 我使用了一个名为myarray的数组来扫描和“读取”我的值,但它不起作用,我不明白为什么 这是我的代码:

@echo off
set myarray[1]=myfield1#myfield2#mysubfield31;mysubfield32#myfield4
for /f "tokens=1-9 delims=#" %%a in ('echo %myarray[1]%') do (
    echo field1 is %%a
    echo field2 is %%b
    echo field3 is %%c
    echo field4 is %%d
    for /f "tokens=1-9 delims=;" %%k in ('echo %%c') do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
    )
)

输出如下:

field1 is myfield1
field2 is myfield2
field3 is mysubfield31 mysubfield32
field4 is myfield4
subfield3 is mysubfield31 mysubfield32
subfield3 is

为什么我不能简单地获得:

subfield3 is mysubfield31 
subfield3 is mysubfield32

其中是“;”用作第二部分中的分隔符?

3 个答案:

答案 0 :(得分:5)

这有效:

@echo off
set myarray[1]=myfield1#myfield2#mysubfield31;mysubfield32#myfield4
for /f "tokens=1-9 delims=#" %%a in ("%myarray[1]%") do (
    echo field1 is %%a
    echo field2 is %%b
    echo field3 is %%c
    echo field4 is %%d
    for /f "tokens=1-9 delims=;" %%k in ("%%c") do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
    )
)
pause

答案 1 :(得分:1)

for /f "tokens=1-9 delims=#" %%a in ("%myarray[1]%") do (

可能会更好......

答案 2 :(得分:-1)

那是documented behavior,分号被视为空格(不是for循环,而是由子shell执行echo命令)。这会导致分号被替换为空格,因此echo field3 is %%c生成输出field3 is mysubfield31 mysubfield32。从内部循环中删除delims=;,因此它使用默认分隔符(空格和制表符),或选择不同的分隔符,并且脚本应按预期工作。但请注意,当嵌套“数组”的字段包含空格时,依赖内部循环中的默认分隔符可能会产生不希望的结果。

证明:

  1. 证明根本原因:

    for /f "tokens=*" %%a in ('echo.a#b;c#d^|find ";"') do echo _%%a_
    

    输出:无(即在回显的字符串中找不到分号)

    for /f "tokens=*" %%a in ('echo.a#b;c#d^|find " "') do echo _%%a_
    

    输出:_a#b c#d_

    显然,这适用于所有delimiter characters,;=,空格和制表符),因为我可以为每个人重现此行为。

  2. 带有输入字符串a#b;c#d的简化脚本:

    @echo off
    set "foo=a#b;c#d"
    for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
      echo field1 is %%a
      echo field2 is %%b
      echo field3 is %%c
      for /f "tokens=1-2 delims=;" %%k in ('echo %%b') do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
      )
    )
    

    输出:

    field1 is a
    field2 is b c
    field3 is d
    subfield3 is b c
    subfield3 is

    注意输出中2 nd 和4 th 行中bc之间的空格。

  3. 与2.相同的脚本,但从内循环中移除了delims=;

    @echo off
    set "foo=a#b;c#d"
    for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
      echo field1 is %%a
      echo field2 is %%b
      echo field3 is %%c
      for /f "tokens=1-2" %%k in ('echo %%b') do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
      )
    )
    

    输出:

    field1 is a
    field2 is b c
    field3 is d
    subfield3 is b
    subfield3 is c

    请注意,嵌套的“数组”b;c(来自变量%foo%)现在会被处理为正确的输出(第4行和第5行)。这是因为空格和制表符是for /f循环中的默认分隔符。

  4. 与2.相同的脚本,但使用+作为嵌套“数组”的分隔符:

    @echo off
    set "foo=a#b+c#d"
    for /f "tokens=1-3 delims=#" %%a in ('echo %foo%') do (
      echo field1 is %%a
      echo field2 is %%b
      echo field3 is %%c
      for /f "tokens=1-2 delims=+" %%k in ('echo %%b') do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
      )
    )
    

    输出:

    field1 is a
    field2 is b+c
    field3 is d
    subfield3 is b
    subfield3 is c

    请注意,2 nd 输出行不再包含虚假空间,并且再次正确处理嵌套的“数组”(第4行和第5行)。


  5. 为了完整性:更好的解决方案是完全删除echo并简单地循环使用双引号字符串,如foxidrivePeter Wright所示,因为它完全避免了这个问题。

    @echo off
    set "foo=a#b;c#d"
    for /f "tokens=1-3 delims=#" %%a in ("%foo%") do (
      echo field1 is %%a
      echo field2 is %%b
      echo field3 is %%c
      for /f "tokens=1-2 delims=;" %%k in ("%%b") do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
      )
    )
    

    dbenham提出的另一个解决方案是启用延迟扩展并在运行时扩展变量:

    @echo off
    setlocal EnableDelayedExpansion
    set "foo=a#b;c#d"
    for /f "tokens=1-3 delims=#" %%a in ('echo !foo!') do (
      echo field1 is %%a
      echo field2 is %%b
      echo field3 is %%c
      for /f "tokens=1-2 delims=;" %%k in ('echo %%b') do (
        echo subfield3 is %%k
        echo subfield3 is %%l       
      )
    )
    

    然而,更好的解决方案是完全删除批处理并切换到实际支持数组的语言,例如PowerShell中。