windows 嵌套批处理循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4334209/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:49:18  来源:igfitidea点击:

Nested batch for loops

windowsloopsbatch-filefor-loopnested

提问by Malte Schwerhoff

The following nested for-loop drives me mad (on Windows 7):

以下嵌套的 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
)

I tried various solutions involving disabling DelayedExpansion, call-statements and whatnot, but I never got the inner loop working. I know that I could replace the inner loop by a subroutine call, but there gotta be a way to make it work with nested loops.

我尝试了各种解决方案,包括禁用 DelayedExpansion、调用语句等,但我从来没有让内部循环工作。我知道我可以通过子例程调用替换内部循环,但是必须有一种方法可以使其与嵌套循环一起工作。

采纳答案by Ben Voigt

What if you used pushd !CTD!and popd, and let FOR /Rdefault to using the current directory?

如果你使用pushd !CTD!and popd,并让FOR /R默认使用当前目录怎么办?

回答by Malte Schwerhoff

Just to give an example of a nested loop that works:

只是举一个有效的嵌套循环的例子:

@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
  )
)

The output (at least on Windows 7) is

输出(至少在 Windows 7 上)是

alpha -> eins
alpha -> zwo
alpha -> alpha
beta -> eins
beta -> zwo
beta -> beta
gamma -> eins
gamma -> zwo
gamma -> gamma

This supports jeb's observation that variable expansion in loops works if they occur inside parenthesis (even without delayed expansion).

这支持 jeb 的观察,即如果循环中的变量扩展发生在括号内(即使没有延迟扩展),它们也会起作用。

回答by Ryan Bemrose

Because nobody has mentioned it, here is the solution using batch subroutines and the CALLcommand.

因为没有人提到过,这里是使用批处理子程序和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

I know GOTO is not very popular, but batch files were originally designed to use labels for control flow. The parenthetized control structure syntax was added later, and this question is an example of where it breaks down. The problem lends itself well to batch subroutines.

我知道 GOTO 不是很流行,但批处理文件最初设计为使用标签进行控制流。括号中的控制结构语法是后来添加的,这个问题是它崩溃的一个例子。这个问题很适合批处理子程序。

回答by jeb

It's not obvious! It's the special parsing of FOR!
A FORcommand is parsed directly after the escape/special character phase (for detecting the parenthesis), but as a result you can't using delayed or %%var expansion as parameters.

这不明显!这是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
  )
)

And also this can't work:

而且这也行不通:

set chars=abc
FOR /F "delims=!chars!" %%N in (bla) DO ....  

does not set a, band cas delims, but !, c, h, aand rinstead.

不会将abc 设置为 delims,但是, c, h, ar代替。

EDIT:Within the parentheses the delayed expansion does work as expected however:

编辑:在括号内,延迟扩展确实按预期工作,但是:

set var=C:\temp
For %%a in (!var!) DO echo %%a

I would expect that you have to use a function to solve your problem.

我希望您必须使用一个函数来解决您的问题。

回答by u8917485

Quote Malte Schwerhoff's Answer

引用 Malte Schwerhoff 的回答

If you don't want to repeat B, you can simply add "if" statement

如果你不想重复 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
    )
  )
)

output:

输出:

alpha -> eins
alpha -> zwo
beta -> eins
beta -> zwo
gamma -> eins
gamma -> zwo