Nested batch for loops

后端 未结 6 1591
面向向阳花
面向向阳花 2020-12-25 13:04

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

@echo off
SetLocal EnableDelayedExpansion

set TESTDIRS=fast mid slow
set TD=src\\test\\resources         


        
相关标签:
6条回答
  • 2020-12-25 13:14

    According to FOR help, FOR /R "Walks the directory tree rooted at [drive:]path, executing the FOR statement in each directory of the tree."

    What may be at issue is the word 'walk'. It seems to me that a walk doesn't occur until one takes the first step and if no step occurs then no walk occurs. Since in this case the walk begins in directory 'fast' and there are no subdirectories, no first step is possible.

    However, if you change the second FOR to:

    for /R !CTD!\..\ %%f in (*.fs) do (echo %%f)
    

    then the result echoed is:

    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
    

    Is that what OP was looking 'FOR'? If so, it would be because now there is someplace to recurse from, that being the parent dir.

    (Note: in this test the dirs fast, mid, slow contained one file each, F1.fs, F2.fs and F3.fs, respectively.)

    0 讨论(0)
  • 2020-12-25 13:24

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

    0 讨论(0)
  • 2020-12-25 13:27

    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

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

    0 讨论(0)
  • 2020-12-25 13:30

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

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

    0 讨论(0)
  • 2020-12-25 13:33

    Quote Malte Schwerhoff's Answer

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

    @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
    
    0 讨论(0)
  • 2020-12-25 13:37

    It's not obvious! It's the special parsing of FOR!
    A FOR command 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 %%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, b and c as delims, but !, c, h, a and r instead.

    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.

    0 讨论(0)
提交回复
热议问题