Here is an improved version of your code including the solution to search the source directory recursively. For this I assumed that the target directory is flat, so no sub-directories are to be copied from the source directory. So here is the code:
@echo off
set "Source=C:\users\directory"
set "Target=C:\users\target"
set "FileList=C:\users\lookup\list.txt"
echo/
if not exist "%Source%" echo Source folder "%Source%" not found & goto :Quit
if not exist "%FileList%" echo File list "%FileList%" not found & goto :Quit
2> nul md "%Target%"
for /F usebackq^ delims^=^ eol^= %%a in ("%FileList%") do (
for /F "delims=" %%b in ('dir /B /S /A:-D "%Source%\%%a"') do (
move "%%b" "%Target%"
)
)
:Quit
echo/
echo Press the Space bar to close this window.
pause > nul
Besides some minor syntax improvements, the major change is the additional nested for /F %%b
loop, which parses the output of a dir
command, which in turn searches for each file name given by %%a
also in the sub-directories of the source directory.
In case you want the respective sub-directories in the source directory to be copied to the target directory, so the target directory is recursive, the script needs to be adapted:
@echo off
set "Source=C:\users\directory"
set "Target=C:\users\target"
set "FileList=C:\users\lookup\list.txt"
echo/
if not exist "%Source%" echo Source folder "%Source%" not found & goto :Quit
if not exist "%FileList%" echo File list "%FileList%" not found & goto :Quit
for /D %%d in ("%Source%") do set "Source=%%~fd"
2> nul md "%Target%"
for /F usebackq^ delims^=^ eol^= %%a in ("%FileList%") do (
for /F "delims=" %%b in ('dir /B /S /A:-D "%Source%\%%a"') do (
set "Item=%%b"
set "Parent=%%~dpb."
setlocal EnableDelayedExpansion
set "Parent=!Parent:*%Source%=.!"
2> nul md "!Target!\!Parent!"
move "!Item!" "!Target!\!Parent!"
endlocal
)
)
:Quit
echo/
echo Press the Space bar to close this window.
pause > nul
This is what I did:
- added line
for /D %%d in ("%Source%") do set "Source=%%~fd"
, which does nothing but get the full absolute and resolved path to the source directory from the given one; this is necessary because there are some string manipulations done on paths (for instance, C:\USERS\.\directory
is equivalent to C:\Users\any\..\Directory
as a path, although they are different strings; the for /D
command line resolves such paths to C:\users\directory
);
- inside of the
for /F %%b
loop, %%b
is stored in variable Item
, which constitutes a full path; Parent
stores the full path to the parent directory with \.
appended; for example, if the current item is C:\users\directory\subdir\file.ext
, Parent
holds C:\users\directory\subdir\.
;
- delayed variable expansion is enabled, because the variables
Item
and Parent
are set and read within the same block of code; it is not generally enabled but toggled in the loop in order not to cause any trouble when exclamation marks occur in the paths;
- the line
set "Parent=!Parent:*%Source%=!"
removes the source directory trom the path stored in Parent
; for example, the Parent
path C:\users\directory\subdir\.
becomes .\subdir\.
when the source directory is C:\users\directory
, so the Parent
becomes relative;
2> nul md "!Target!\!Parent!"
ensures that the Parent
directory exists in the target directory (2> nul
suppresses a potential error message);
- finally, the movement is done; for example, when the current item is
C:\users\directory\subdir\file.ext
and the target directory is C:\users\target
, it is moved into the directory C:\users\target\.\subdir\.
, which is equivalent to C:\users\target\subdir
;
Note that the source directory must not contain any !
and =
characters for the script to work!