嵌套批处理 for 循环
Posted
技术标签:
【中文标题】嵌套批处理 for 循环【英文标题】:Nested batch for loops 【发布时间】:2011-05-19 01:34:34 【问题描述】:以下嵌套的 for 循环让我发疯(在 Windows 7 上):
@echo off
SetLocal EnableDelayedExpansion
set TESTDIRS=fast mid slow
set TD=src\test\resources\testsuite
for %%d in (%TESTDIRS%) do (
set CTD=%TD%\%%d
echo CTD: !CTD!
REM Echos the expected path
echo CTD: %CTD%
REM Echos nothing -- understandable
for /R !CTD! %%f in (*.fs) do (echo %%f)
REM Echos nothing -- why?
for /R src\test\resources\testsuite\fast %%f in (*.fs) do (echo %%f)
REM Echos expected files
)
我尝试了各种解决方案,包括禁用 DelayedExpansion、调用语句和诸如此类的东西,但我从来没有让内部循环正常工作。我知道我可以通过子例程调用替换内部循环,但是必须有一种方法可以使它与嵌套循环一起使用。
【问题讨论】:
【参考方案1】:仅举一个有效的嵌套循环示例:
@echo off
SetLocal
set B=alpha beta gamma
set A=eins zwo
FOR %%b in (%B%) do (
FOR %%a in (%A% %%b) DO (
echo %%b -^> %%a
)
)
输出(至少在 Windows 7 上)是
alpha -> eins
alpha -> zwo
alpha -> alpha
beta -> eins
beta -> zwo
beta -> beta
gamma -> eins
gamma -> zwo
gamma -> gamma
这支持了 jeb 的观察,即如果循环中的变量扩展出现在括号内(即使没有延迟扩展),它们也会起作用。
【讨论】:
嗨,我用了你的例子,但它会在最后一个陡峭的地方打印 %%b 而不是 %%a,我在内部循环中只使用 FOR %%a in (%A%) 解决了这个问题 @JuanAntonioOrozco 您可能已经观察到预期的行为。我编辑了我的答案以澄清循环应该打印的内容。【参考方案2】:因为没有人提及,这里是使用批处理子程序和CALL
命令的解决方案。
@echo off
set TESTDIRS=fast mid slow
set TD=src\test\resources\testsuite
for %%d in (%TESTDIRS%) do call :process_testdir %%d
goto :eof
:process_testdir
set CTD=%TD%\%1
echo CTD: %CTD%
REM Echos the expected path
for /R %CTD% %%f in (*.fs) do (echo %%f)
REM Echos as expected
goto :eof
我知道 GOTO 不是很流行,但批处理文件最初设计为使用标签进行控制流。带括号的控制结构语法是后来添加的,这个问题是它分解的一个例子。这个问题很适合批处理子程序。
【讨论】:
【参考方案3】:如果你使用pushd !CTD!
和popd
,让FOR /R
默认使用当前目录呢?
【讨论】:
我会接受这个解决方案,因为它解决了我的示例上下文中的问题。它真的很聪明:-) 这是一种以不同方式解决特定问题的解决方法。它没有解释如何正确嵌套 for 循环(即不回答问题)。我想用不同的用例嵌套for循环,在这种情况下,这种解决方法不能解决问题,而是通过谷歌搜索“批量嵌套for循环”来到这里。 -1 来自我。【参考方案4】:不明显!是FOR的特殊解析!FOR 命令在转义/特殊字符阶段(用于检测括号)之后直接解析,但因此您不能使用延迟或 %%var 扩展作为参数。
FOR %%a in (%%%%B) do (
FOR %%a in (1) DO ( <<< this %%a will not replaced with %%B
echo %%a - shows 1, because %%a is the name of the inner variable
echo %%B - doesn't work
)
)
这也行不通:
set chars=abc
FOR /F "delims=!chars!" %%N in (bla) DO ....
不将a、b和c设置为delims,而是!、c、h、a 和 r。
编辑:在括号内,延迟扩展确实按预期工作:
set var=C:\temp
For %%a in (!var!) DO echo %%a
我希望你必须使用一个函数来解决你的问题。
【讨论】:
抱歉,但我看不出您的回复如何帮助我解决我的问题,因为它只告诉我什么不起作用。另外,我在我的问题中已经提到我知道用子例程替换内部循环的可能性,但我的问题是如何使嵌套循环工作。 抱歉,我想您只能使用 Ben Voigt 的 PUSHD 解决方案。扩展似乎是不可能的,因为内部循环的路径只扩展了一个,在第一个括号的开头,【参考方案5】:引用 Malte Schwerhoff 的回答
如果你不想重复B,你可以简单地添加“if”语句
@echo off
SetLocal
set B=alpha beta gamma
set A=eins zwo
FOR %%b in (%B%) do (
FOR %%a in (%A% %%b) DO (
IF %%b NEQ %%a (
echo %%b -^> %%a
)
)
)
输出:
alpha -> eins
alpha -> zwo
beta -> eins
beta -> zwo
gamma -> eins
gamma -> zwo
【讨论】:
【参考方案6】:根据 FOR 帮助,FOR /R
“遍历以 [drive:]path 为根的目录树,在树的每个目录中执行 FOR 语句。”
可能有问题的是“步行”这个词。在我看来,在迈出第一步之前不会发生步行,如果没有发生任何步骤,则不会发生步行。因为在这种情况下,遍历从目录“fast”开始,并且没有子目录,所以第一步是不可能的。
但是,如果您将第二个 FOR 更改为:
for /R !CTD!\..\ %%f in (*.fs) do (echo %%f)
那么回显的结果是:
CTD: src\test\resources\testsuite\fast
CTD:
C:\FORTEST\src\test\resources\testsuite\fast\F1.fs
C:\FORTEST\src\test\resources\testsuite\mid\F2.fs
C:\FORTEST\src\test\resources\testsuite\slow\F3.fs
C:\FORTEST\src\test\resources\testsuite\fast\F1.fs
CTD: src\test\resources\testsuite\mid
CTD:
C:\FORTEST\src\test\resources\testsuite\fast\F1.fs
C:\FORTEST\src\test\resources\testsuite\mid\F2.fs
C:\FORTEST\src\test\resources\testsuite\slow\F3.fs
C:\FORTEST\src\test\resources\testsuite\fast\F1.fs
CTD: src\test\resources\testsuite\slow
CTD:
C:\FORTEST\src\test\resources\testsuite\fast\F1.fs
C:\FORTEST\src\test\resources\testsuite\mid\F2.fs
C:\FORTEST\src\test\resources\testsuite\slow\F3.fs
C:\FORTEST\src\test\resources\testsuite\fast\F1.fs
这就是 OP 正在寻找的“FOR”吗?如果是这样,那是因为现在有某个地方可以递归,那就是父目录。
(注意:在这个测试中,快速、中、慢三个目录分别包含一个文件,分别为 F1.fs、F2.fs 和 F3.fs。)
【讨论】:
此答案将包括不在%TESTDIRS%
中的目录。正如问题中所述,/R src\test\resources\testsuite\fast %%f
有效,这是set CTD=%TD%\%%d
的预期结果,因此问题不太可能是对树的行走方式的误解。以上是关于嵌套批处理 for 循环的主要内容,如果未能解决你的问题,请参考以下文章
在批处理文件中,如果满足一个条件而不是周围的 for 循环,如何突破嵌套的 if 语句?