1

Im very confused at what's going on here. It should copy all docx found from docs to working directory. but for some reason the %%f inside the for loop shows up as %f. i did an echo and it printed out the folder just fine. the same thing happens to %%r and %r as well. I'm I writing this incorrectly?

set filepath=%1
for /f %%f in ('dir /ad /b %filepath%') do (
if exist "%filepath%\%%f\docs" (
for /r %filepath%\%%f\docs %%r in (*.docx) do (
echo %%f
copy %%r "%cd%\edited"
)
)
)

The output

if exist "C:\Documents\WordDocs\Data1\docs" (for /R C:\Documents\WordDocs\%f\docs %r in (*.docx) do ( 
echo Data1
copy %r "C:\Users\admin\Desktop\Test"
) ) )
Eric
  • 682
  • 2
  • 11
  • 23
  • 2
    but the output display it as %f instead of Data1. do i just use %f instead of %%f? – Eric Oct 02 '17 at 17:03
  • up until the if statement it works fine. its when i tried to use the %%f inside the nested for loop it prints out %f instead of the value it's supposed to be. – Eric Oct 02 '17 at 17:16
  • This is an interesting problem! It seems to be some limitation on the `FOR /R` command, rather than anything to do with the `%` sign. Perhaps the `for /r` command only allows literal parameters and not variables? – Klitos Kyriacou Oct 02 '17 at 17:48
  • Let me paraphrase your issue so that other readers can appreciate it. Simply put, the following command does not work: `for %%f in (C:\Windows) do (for /r "%%f" %%r in (*.tmp) do (echo %%r))` – Klitos Kyriacou Oct 02 '17 at 17:56
  • I noticed this issue many years ago now and was completely perplexed by it. _It's also one of the reasons, I try to use `%%A` whenever possible_. – Compo Oct 02 '17 at 18:12

2 Answers2

2

The for command (like the if command) is parsed earlier than other commands. At this time, for variable references like %%f are not yet recognised. So for /R cannot use a root path containing a for variable reference like %%f. The same is true for the option string of for /F. You can also not use a delayed expanded variable instead of %%f.

The easiest work-around for the script at hand is to use pushd"%filepath%\%%f\docs" before the for /R loop and popd after it, and to let for /R use its default root, namely the current working directory, which has just been set by pushd; the previous one becomes restored by popd. Here is a demonstration of what I mean:

set "filepath=%~1"
for /F %%f in ('dir /A:D /B "%filepath%"') do (
    if exist "%filepath%\%%f\docs" (
        pushd "%filepath%\%%f\docs"
        for /R %%r in ("*.docx") do (
            echo/%%f
            copy "%%~r" "%cd%\edited"
        )
        popd
    )
)

An alternative but more complicated way is to move the for /R loop into a sub-routine, to call it by the call command and to pass the root path as an argument, like this:

set "filepath=%~1"
for /F %%f in ('dir /A:D /B "%filepath%"') do (
    if exist "%filepath%\%%f\docs" (
        call :SUB "%filepath%\%%f\docs"
    )
)
goto :EOF

:SUB
for /R "%~1" %%r in ("*.docx") do (
    echo/%%f
    copy "%%~r" "%cd%\edited"
)
goto :EOF

Reference this post: How does the Windows Command Interpreter (CMD.EXE) parse scripts?

aschipfl
  • 28,946
  • 10
  • 45
  • 77
1

This version doesn't use For /R:

For /F "Delims=" %%A In ('Dir/B/AD-L "%~1"') Do If Exist "%~1\%%A\docs\" (
    For /F "Delims=" %%B In ('Dir/B/S/A-D-L "%~1\%%A\docs\*.docx"'
    ) Do Echo=Copy "%%~B" "%CD%\edited")
Pause

Remove line 4 and Echo= on line 3 if you're happy with the output in the cmd window, remembering to unedit your destination path.

Compo
  • 30,301
  • 4
  • 20
  • 32