【问题标题】:for-loop and delimetersfor循环和分隔符
【发布时间】:2013-06-30 13:37:00
【问题描述】:

我需要一种快速的方法在 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

“;”在哪里在第二个中用作分隔符?

【问题讨论】:

    标签: windows for-loop batch-file cmd


    【解决方案1】:

    这行得通:

    @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
    

    【讨论】:

      【解决方案2】:
      for /f "tokens=1-9 delims=#" %%a in ("%myarray[1]%") do (
      

      可能会更好一点...

      【讨论】:

      • 我编辑了 %array[1]% 名称,这样人们就可以尝试代码,而不会陷入摸不着头脑的困境。在我看到它之前,我花了很多时间编辑并诅咒微软随机 cmd 行为。 :)
      【解决方案3】:

      那是documented behavior,分号被视为空格(不是由for 循环,而是由执行echo 命令的子shell)。这会导致分号被替换为空格,以便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

        注意输出的第 2nd 和第 4th 行中 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

        请注意,第 2nd 输出行不再包含虚假空间,并且嵌套的“数组”再次得到正确处理(第 4 行和第 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。

      【讨论】:

      • 错了!分号在普通(无 /F 选项)FOR 命令中被视为分隔符。在FOR /F 命令中,分隔符正是放在delims=... 选项中的分隔符。
      • 在某些情况下它是分隔符是对的,但建议从“delims=;”中删除它是错误的作为解决方案。
      • @AnsgarWiechers:再来一次:分号在for /F 命令中被NOT视为空格;您链接中的文章 NOT 引用了for /F 命令,而是引用了批处理文件参数(以及 FOR with NO /F option 的扩展名)。有趣的是,在您的示例的第 2 点中,当正在处理的值为 b c 时,您说“请注意,嵌套的“数组”b;c 现在是正确的 processec”!此问题与for 命令的处理无关,而是与删除分号的b c 字符串的生成有关。
      • 从您上面回答的第一行复制:“这是记录在案的行为,分号被视为空格”。在您最后发表评论之前,您没有说过“替换”(您可以在此页面中找到以确认它)。当然,整个话题都是关于for /f命令的!不是吗?
      • @AnsgarWiechers - 你在正确的轨道上 ; 在 FOR /F IN() 子句中处理时被视为空格。但是您提出的简单更改定界符的解决方案完全没有达到目的。您的“解决方案”恰好起作用,因为没有一个数据字段包含空格。但如果它们确实包含空格,它将失败。适当的解决方案保留;。理想情况下使用字符串而不是命令:in ("%myarray[1]%")。或者通过命令使用延迟扩展:in ('echo !myarray[1]!')
      猜你喜欢
      • 1970-01-01
      • 2013-03-16
      • 2012-04-19
      • 2014-01-19
      • 1970-01-01
      • 2012-01-23
      • 1970-01-01
      • 1970-01-01
      • 2012-12-24
      相关资源
      最近更新 更多