在批处理文件中打破嵌套for循环

时间:2013-01-28 12:45:57

标签: batch-file

在遇到这个问题两次后,我想我会在这里发布,看看是否有人知道如何绕过它。

我似乎无法使用goto打破嵌套循环,因为它看起来就像它突破内循环时,括号因此从未到达内部结束循环。

我已将其缩小为一个非常简单的例子

for %%a in (1,2,3) do (
for %%b in (4,5,6) do (
echo Breaking
goto :BREAK
)
:BREAK
)

这会导致错误

) was unexpected at this time.

我认为可能添加额外的括号可能会解决问题,但除非我知道我要打破,否则它将无法解决,如果这是一个有条件的突破,那就是同样的问题。

是否有任何简单的替代方法可以将内循环分解回外部,即使是使用ifelse的条件中断?

6 个答案:

答案 0 :(得分:10)

通过在标签中放置内循环来中断。

for %%a in (1, 2, 3) DO (

   call :innerloop 
)
:innerloop
for %%b in (4, 5, 6) DO (
  if %%b==<something> (
    echo    break
    goto :break
  )

)
:break

答案 1 :(得分:5)

在中断后,您还可以省略与FOR:

相关联的控制变量的剩余迭代次数
@echo off
for %%a in (1,2,3) do (
   echo Top-level loop: %%a
   set break=
   for %%b in (4,5,6) do if not defined break (
      echo Nested loop: %%a-%%b
      if %%b == 4 (
         echo Breaking
         set break=yes
      )
   )
)

此方法将嵌套for-body的代码保留在其原始位置,并允许在for-body内的多个点处轻松设置中断。

安东尼奥

答案 2 :(得分:0)

安东尼奥的建议非常好。我在我的例子中用它来解析文件列表中的一些CSV或HTML文件。 (嵌套for循环)。首先查看解析文件列表,第二个解析每个文件的内容。分离器要么是;或/.

@dir /O /B j:\temp\*.txt > j:\temp\filelist.doc
@for /F "tokens=1" %%a in (j:\temp\filelist.doc) DO (
 @echo j:\temp\%%a
 @set ef=
 @for /F "delims=;/ tokens=1,2,3,4,5,6,7*" %%b in (j:\temp\%%a) DO @if not defined ef (
  @if %%e == CNAME (
   @echo Do something here
   @set ef=yes
  )
 )
)

答案 3 :(得分:0)

DEFINED可以为多个reasons做恶。除非您确切知道它是如何工作的以及所有潜在的用例,否则我不建议使用它。

  

最好避免使用任何分隔符(空格,   变量名中的逗号等),例如IF DEFINED _variable   如果变量名称包含分隔符,则通常会失败。

更安全的答案,也不使用EXITGOTO

@echo off

SETLOCAL ENABLEDELAYEDEXPANSION

Set time_to_exit=false

FOR /L %%O IN (1,1,3) DO (
    echo [  Outer  ] loop iteration %%O
    FOR /L %%I IN (1,1,3) DO (
        IF NOT "!time_to_exit!"=="true" (
            echo ]Inner[ loop iteration %%I
            IF "%%O"=="2" Set time_to_exit=true
        )
    )
)

输出:

[  Outer  ] loop iteration 1
]Inner[ loop iteration 1
]Inner[ loop iteration 2
]Inner[ loop iteration 3
[  Outer  ] loop iteration 2
]Inner[ loop iteration 1
[  Outer  ] loop iteration 3

答案 4 :(得分:0)

欢迎使用 DOS BAT 及其所有常见故障。原来DOS BAT不支持嵌套循环_at _all;他们仍然不能完全正确地工作。为避免所有故障、怪异和不一致,请改用 Microsoft PowerShell。

您可以通过重构脚本以使用由“call”语句调用的内部子例程来避免嵌套循环。使每个“for”执行一个调用子例程的语句,而不是将操作放在内联块中。

一个密切相关的问题是,即使跳出顶级循环似乎也不太常见。那是因为 '( ... )' 便利结构是在原始语言出现几年后用螺栓固定在 BAT 语言上的,并且与该语言的其余部分不能很好地配合使用。特别是,当第一次进入块时,'( ... )' 中的 _everything 被一劳永逸地替换。像 'if %NOMORE%==yes ...' 这样的构造行为不正常,因为 %NOMORE% 的值在块被输入时只被替换一次, _not 每次执行时都像你期望的那样。因此,如果该值稍后被循环内部或外部的任何内容更改,则“if”测试将_看不到新值。

解决这个问题的一种方法是笨拙地重组你的 BAT 文件,要么使用一堆“goto”,以便它不使用“( ... )”,要么调用一堆其他不需要的子程序,或者两者兼而有之——这就是 BAT wallahs 在引入块的语法便利性之前多年所做的事情(伴随着它的奇怪行为)。解决此问题的更好方法是使用“延迟扩展”(即“if !NOMORE!==yes ...”而不是“if %NOMORE%==yes ...”)。 [您的 Windows 版本必须支持延迟扩展,并且必须在您的 setlocal 语句中启用。]


由于新信息和对评论的回应,进行了大量编辑。 (有关更多信息,请参阅第一条评论。)

答案 5 :(得分:-1)

您能否提供有关您的要求的更多信息? 在此期间,如果符合您的要求,您可以试试这个。 如果您需要更多,请随时发布。

@echo off
for %%a in (1,2,3) do ( 
for %%b in (4,5,6) do (
echo Breaking
goto Break 
)
)
:Break