Folder1 and Folder2 logs not showing correctly in

2019-08-21 07:14发布

问题:

This should be simple but is not working correctly.

FOR /D %%d IN ("D:\Folder*") DO (
    FOR /R "%%d\logs" %%i IN (*) do echo %%i
)
pause

I have also tried:

FOR /D %%d IN ("D:\Folder*") DO (
    SET fld=%%d
    FOR /R "%fld%\logs" %%i IN (*) do echo %%i
)
pause

I feel that am missing something pretty basic.

Thanks!

回答1:

First code

FOR /D %%d IN ("D:\Folder*") DO (
    FOR /R "%%d\logs" %%i IN (*) do echo %%i
)

fails because you can not use a for replaceable parameter in the folder of a for /r. In the way the for parser works, the value to use as the starting folder used in the /R must be available before the for /d starts to execute.

Second code

FOR /D %%d IN ("D:\Folder*") DO (
    SET fld=%%d
    FOR /R "%fld%\logs" %%i IN (*) do echo %%i
)

fails because %fld% will not be parsed as you think. The full for /d %%d is parsed as only one command and all the %var% references inside this command are removed, being replaced with the value stored in the variables before starting to execute. You can not change a variable's value and retrieve the changed value inside the same command because while executing there is not any variable expansion included in the command, only the values the variables had when the command was parsed.

This is usually handled enabling delayed expansion so you can change where needed %var% into !var! to indicate to the parser that the variable expansion (value retrieval) should be delayed until the command is executed. So you could write something like

setlocal enabledelayedexpansion
FOR /D %%d IN ("D:\Folder*") DO (
    SET "fld=%%d"
    FOR /R "!fld!\logs" %%i IN (*) do echo %%i
)

BUT this will also not work, for the same reason indicated in the first code. The value to use in /R is required at parse time.

So, how to solve the problem?

You can avoid having to indicate the folder in the /R by first changing the current active directory to the folder being iterated by for /D %%i

for /d %%d in ("d:\Folder*") do (
    pushd "%%~fd\logs" && (
        for /r %%i in (*) do echo %%i
        popd
    )
)

or you can place the inner loop in a separate subroutine

for /d %%d in ("d:\Folder*") do call :process "%%d"
goto :eof


:process folderPath
for /r "%~1\logs" %%i in (*) do echo %%i
goto :eof

or you can replace the inner recursive for with a for /f processing a recursive dir

for /d %%d in ("d:\Folder*") do (
    for /f "delims=" %%i in ('dir "%%~fd\logs" /a-d /b /s`) do echo %%i
)


回答2:

You could also just simplify it.

For /D %%A In ("D:\Folder*") Do Where/R "%%~A" *