[windows] How to copy a directory structure but only include certain files (using windows batch files)

As the title says, how can I recursively copy a directory structure but only include some files. E.g given the following directory structure:

folder1
  folder2
    folder3
      data.zip
      info.txt
      abc.xyz
    folder4
    folder5
      data.zip
      somefile.exe
      someotherfile.dll

The files data.zip and info.txt can appear everywhere in the directory structure. How can I copy the full directory structure, but only include files named data.zip and info.txt (all other files should be ignored)?

The resulting directory structure should look like this:

copy_of_folder1
  folder2
    folder3
      data.zip
      info.txt
    folder4
    folder5
      data.zip

This question is related to windows batch-file cmd robocopy

The answer is


To do this with drag and drop use winzip there's a dir structure preserve option. Simply create a new .zip at the directory level which will be your root and drag files in.


That's only two simple commands, but I wouldn't recommend this, unless the files that you DON'T need to copy are small. That's because this will copy ALL files and then remove the files that are not needed in the copy.

xcopy /E /I folder1 copy_of_folder1
for /F "tokens=1 delims=" %i in ('dir /B /S /A:-D copy_of_files ^| find /V "info.txt" ^| find /V "data.zip"') do del /Q "%i"

Sure, the second command is kind of long, but it works!

Also, this approach doesn't require you to download and install any third party tools (Windows 2000+ BATCH has enough commands for this).


That's only two simple commands, but I wouldn't recommend this, unless the files that you DON'T need to copy are small. That's because this will copy ALL files and then remove the files that are not needed in the copy.

xcopy /E /I folder1 copy_of_folder1
for /F "tokens=1 delims=" %i in ('dir /B /S /A:-D copy_of_files ^| find /V "info.txt" ^| find /V "data.zip"') do del /Q "%i"

Sure, the second command is kind of long, but it works!

Also, this approach doesn't require you to download and install any third party tools (Windows 2000+ BATCH has enough commands for this).


XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDIT: If you want to preserve the empty folders (which, on rereading your post, you seem to) use /E instead of /S.


try piping output of find (ie. the file path) into cpio

find . -type f -name '*.jpg' | cpio -p -d -v targetdir/

cpio checks timestamp on target files -- so its safe and fast.

remove -v for faster op, once you get used to it.


XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDIT: If you want to preserve the empty folders (which, on rereading your post, you seem to) use /E instead of /S.


An alternate solution that copies one file at a time and does not require ROBOCOPY:

@echo off
setlocal enabledelayedexpansion

set "SOURCE_DIR=C:\Source"
set "DEST_DIR=C:\Destination"
set FILENAMES_TO_COPY=data.zip info.txt

for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
    if exist "%%F" (
        set FILE_DIR=%%~dpF
        set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
        xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
    )
)

The outer for statement generates any possible path combination of subdirectory in SOURCE_DIR and name in FILENAMES_TO_COPY. For each existing file xcopy is invoked. FILE_INTERMEDIATE_DIR holds the file's subdirectory path within SOURCE_DIR which needs to be created in DEST_DIR.


Thanks To Previous Answers. :)

This script named "r4k4copy.cmd":

@echo off
for %%p in (SOURCE_DIR DEST_DIR FILENAMES_TO_COPY) do set %%p=
cls
echo :: Copy Files Including Folder Tree
echo :: http://stackoverflow.com
rem     /questions/472692/how-to-copy
rem     -a-directory-structure-but-only
rem     -include-certain-files-using-windows
echo :: ReScripted by r4k4
echo.
if "%1"=="" goto :NoParam
if "%2"=="" goto :NoParam
if "%3"=="" goto :NoParam
setlocal enabledelayedexpansion
set SOURCE_DIR=%1
set DEST_DIR=%2
set FILENAMES_TO_COPY=%3
for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
if exist "%%F" (
set FILE_DIR=%%~dpF
set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
)
)
goto :eof
:NoParam
echo.
echo Syntax: %0 [Source_DIR] [Dest_DIR] [FileName]
echo Eg.   : %0 D:\Root E:\Root\Lev1\Lev2\Lev3 *.JPG
echo Means : Copy *.JPG from D:\Root to E:\Root\Lev1\Lev2\Lev3

It accepts variable of "Source", "Destination", and "FileName". It also can only copying specified type of files or selective filenames.

Any improvement are welcome. :)


With find and cp only:

mkdir /tmp/targetdir
cd sourcedir
find . -type f -name '*.zip' -exec cp -p --parents {} /tmp/targetdir ";"
find . -type f -name '*.txt' -exec cp -p --parents {} /tmp/targetdir ";"

Similar to Paulius' solution, but the files you don't care about are not copied then deleted:

@echo OFF

:: Replace c:\temp with the directory where folder1 resides.
cd c:\temp

:: You can make this more generic by passing in args for the source and destination folders.
for /f "usebackq" %%I in (`dir /b /s /a:-d folder1`) do @echo %%~nxI | find /V "data.zip" | find /v "info.txt" >> exclude_list.txt
xcopy folder1 copy_of_folder1 /EXCLUDE:exclude_list.txt /E /I

If Powershell is an option, you can do this:

Copy-Item c:\sourcePath d:\destinationPath -filter data.zip -recurse

The main disadvantage is it copies all folders, even if they will end up being empty because no files match the filter you specify. So you could end up with a tree full of empty folders, in addition to the few folders that have the files you want.


To copy all text files to G: and preserve directory structure:

xcopy *.txt /s G:

If Powershell is an option, you can do this:

Copy-Item c:\sourcePath d:\destinationPath -filter data.zip -recurse

The main disadvantage is it copies all folders, even if they will end up being empty because no files match the filter you specify. So you could end up with a tree full of empty folders, in addition to the few folders that have the files you want.


Under Linux and other UNIX systems, using the tar command would do this easily.

$ tar cvf /tmp/full-structure.tar *data.zip *info.txt

Then you'd cwd to the target and:

$ tar xvf /tmp/full-structure.tar 

Of course you could pipe the output from the first tar into the 2nd, but seeing it work in steps is easier to understand and explain. I'm missing the necessary cd /to/new/path/ in the following command - I just don't recall how to do it now. Someone else can add it, hopefully.

$ tar cvf -  *data.zip *info.txt |  tar xvf - 

Tar (gnutar) is available on Windows too, but I'd probably use the xcopy method myself on that platform.


try piping output of find (ie. the file path) into cpio

find . -type f -name '*.jpg' | cpio -p -d -v targetdir/

cpio checks timestamp on target files -- so its safe and fast.

remove -v for faster op, once you get used to it.


For those using Altap Salamander (2 panels file manager) : in the Options of the Copy popup, just specify the file names or masks. Easy.


Under Linux and other UNIX systems, using the tar command would do this easily.

$ tar cvf /tmp/full-structure.tar *data.zip *info.txt

Then you'd cwd to the target and:

$ tar xvf /tmp/full-structure.tar 

Of course you could pipe the output from the first tar into the 2nd, but seeing it work in steps is easier to understand and explain. I'm missing the necessary cd /to/new/path/ in the following command - I just don't recall how to do it now. Someone else can add it, hopefully.

$ tar cvf -  *data.zip *info.txt |  tar xvf - 

Tar (gnutar) is available on Windows too, but I'd probably use the xcopy method myself on that platform.


An alternate solution that copies one file at a time and does not require ROBOCOPY:

@echo off
setlocal enabledelayedexpansion

set "SOURCE_DIR=C:\Source"
set "DEST_DIR=C:\Destination"
set FILENAMES_TO_COPY=data.zip info.txt

for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
    if exist "%%F" (
        set FILE_DIR=%%~dpF
        set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
        xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
    )
)

The outer for statement generates any possible path combination of subdirectory in SOURCE_DIR and name in FILENAMES_TO_COPY. For each existing file xcopy is invoked. FILE_INTERMEDIATE_DIR holds the file's subdirectory path within SOURCE_DIR which needs to be created in DEST_DIR.


Thanks To Previous Answers. :)

This script named "r4k4copy.cmd":

@echo off
for %%p in (SOURCE_DIR DEST_DIR FILENAMES_TO_COPY) do set %%p=
cls
echo :: Copy Files Including Folder Tree
echo :: http://stackoverflow.com
rem     /questions/472692/how-to-copy
rem     -a-directory-structure-but-only
rem     -include-certain-files-using-windows
echo :: ReScripted by r4k4
echo.
if "%1"=="" goto :NoParam
if "%2"=="" goto :NoParam
if "%3"=="" goto :NoParam
setlocal enabledelayedexpansion
set SOURCE_DIR=%1
set DEST_DIR=%2
set FILENAMES_TO_COPY=%3
for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
if exist "%%F" (
set FILE_DIR=%%~dpF
set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
)
)
goto :eof
:NoParam
echo.
echo Syntax: %0 [Source_DIR] [Dest_DIR] [FileName]
echo Eg.   : %0 D:\Root E:\Root\Lev1\Lev2\Lev3 *.JPG
echo Means : Copy *.JPG from D:\Root to E:\Root\Lev1\Lev2\Lev3

It accepts variable of "Source", "Destination", and "FileName". It also can only copying specified type of files or selective filenames.

Any improvement are welcome. :)


For those using Altap Salamander (2 panels file manager) : in the Options of the Copy popup, just specify the file names or masks. Easy.


Using WinRAR command line interface, you can copy the file names and/or file types to an archive. Then you can extract that archive to whatever location you like. This preserves the original file structure.

I needed to add missing album picture files to my mobile phone without having to recopy the music itself. Fortunately the directory structure was the same on my computer and mobile!

I used:

   rar a -r C:\Downloads\music.rar X:\music\Folder.jpg
  • C:\Downloads\music.rar = Archive to be created
  • X:\music\ = Folder containing music files
  • Folder.jpg = Filename I wanted to copy

This created an archive with all the Folder.jpg files in the proper subdirectories.

This technique can be used to copy file types as well. If the files all had different names, you could choose to extract all files to a single directory. Additional command line parameters can archive multiple file types.

More information in this very helpful link http://cects.com/using-the-winrar-command-line-tools-in-windows/


XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDIT: If you want to preserve the empty folders (which, on rereading your post, you seem to) use /E instead of /S.


That's only two simple commands, but I wouldn't recommend this, unless the files that you DON'T need to copy are small. That's because this will copy ALL files and then remove the files that are not needed in the copy.

xcopy /E /I folder1 copy_of_folder1
for /F "tokens=1 delims=" %i in ('dir /B /S /A:-D copy_of_files ^| find /V "info.txt" ^| find /V "data.zip"') do del /Q "%i"

Sure, the second command is kind of long, but it works!

Also, this approach doesn't require you to download and install any third party tools (Windows 2000+ BATCH has enough commands for this).


With find and cp only:

mkdir /tmp/targetdir
cd sourcedir
find . -type f -name '*.zip' -exec cp -p --parents {} /tmp/targetdir ";"
find . -type f -name '*.txt' -exec cp -p --parents {} /tmp/targetdir ";"

To copy all text files to G: and preserve directory structure:

xcopy *.txt /s G:

XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDIT: If you want to preserve the empty folders (which, on rereading your post, you seem to) use /E instead of /S.


That's only two simple commands, but I wouldn't recommend this, unless the files that you DON'T need to copy are small. That's because this will copy ALL files and then remove the files that are not needed in the copy.

xcopy /E /I folder1 copy_of_folder1
for /F "tokens=1 delims=" %i in ('dir /B /S /A:-D copy_of_files ^| find /V "info.txt" ^| find /V "data.zip"') do del /Q "%i"

Sure, the second command is kind of long, but it works!

Also, this approach doesn't require you to download and install any third party tools (Windows 2000+ BATCH has enough commands for this).


To do this with drag and drop use winzip there's a dir structure preserve option. Simply create a new .zip at the directory level which will be your root and drag files in.


Using WinRAR command line interface, you can copy the file names and/or file types to an archive. Then you can extract that archive to whatever location you like. This preserves the original file structure.

I needed to add missing album picture files to my mobile phone without having to recopy the music itself. Fortunately the directory structure was the same on my computer and mobile!

I used:

   rar a -r C:\Downloads\music.rar X:\music\Folder.jpg
  • C:\Downloads\music.rar = Archive to be created
  • X:\music\ = Folder containing music files
  • Folder.jpg = Filename I wanted to copy

This created an archive with all the Folder.jpg files in the proper subdirectories.

This technique can be used to copy file types as well. If the files all had different names, you could choose to extract all files to a single directory. Additional command line parameters can archive multiple file types.

More information in this very helpful link http://cects.com/using-the-winrar-command-line-tools-in-windows/


I am fine with regular expressions, lazy and averse to installs, so I created a batch file that creates the directory and copies with vanilla DOS commands. Seems laborious but quicker for me than working out robocopy.

  1. Create your list of source files with complete paths, including drive letter if nec, in a text file.
  2. Switch on regular expressions in your text editor.
  3. Add double quotes round each line in case of spaces - search string (.*) replace string "\1", and click replace all
  4. Create two lines per file - one to create the directory, one to copy the file (qqq will be replaced with destination path) - search string (.*) replace string md qqq\1\nxcopy \1 qqq\1\n and click replace all
  5. Remove the filename from the destination paths – search \\([^\\^"]+)"\n replace \\"\n
  6. Replace in the destination path (in this example A:\src and B:\dest). Turn OFF regular expressions, search qqq"A:\src\ replace B:\dest\ and click replace all.

md will create nested directories. copy would probably behave identically to xcopy in this example. You might want to add /Y to xcopy to suppress overwrite confirms. You end up with a batch file like so:

md "B:\dest\a\b\c\"
xcopy "C:\src\a\b\c\e.xyz" "B:\dest\a\b\c\e.xyz"

repeated for every file in your original list. Tested on Win7.


Similar to Paulius' solution, but the files you don't care about are not copied then deleted:

@echo OFF

:: Replace c:\temp with the directory where folder1 resides.
cd c:\temp

:: You can make this more generic by passing in args for the source and destination folders.
for /f "usebackq" %%I in (`dir /b /s /a:-d folder1`) do @echo %%~nxI | find /V "data.zip" | find /v "info.txt" >> exclude_list.txt
xcopy folder1 copy_of_folder1 /EXCLUDE:exclude_list.txt /E /I

Examples related to windows

"Permission Denied" trying to run Python on Windows 10 A fatal error occurred while creating a TLS client credential. The internal error state is 10013 How to install OpenJDK 11 on Windows? I can't install pyaudio on Windows? How to solve "error: Microsoft Visual C++ 14.0 is required."? git clone: Authentication failed for <URL> How to avoid the "Windows Defender SmartScreen prevented an unrecognized app from starting warning" XCOPY: Overwrite all without prompt in BATCH Laravel 5 show ErrorException file_put_contents failed to open stream: No such file or directory how to open Jupyter notebook in chrome on windows Tensorflow import error: No module named 'tensorflow'

Examples related to batch-file

'ls' is not recognized as an internal or external command, operable program or batch file '' is not recognized as an internal or external command, operable program or batch file XCOPY: Overwrite all without prompt in BATCH Can´t run .bat file under windows 10 Execute a batch file on a remote PC using a batch file on local PC Windows batch - concatenate multiple text files into one How do I create a shortcut via command-line in Windows? Getting Error:JRE_HOME variable is not defined correctly when trying to run startup.bat of Apache-Tomcat Curl not recognized as an internal or external command, operable program or batch file Best way to script remote SSH commands in Batch (Windows)

Examples related to cmd

'ls' is not recognized as an internal or external command, operable program or batch file '' is not recognized as an internal or external command, operable program or batch file XCOPY: Overwrite all without prompt in BATCH VSCode Change Default Terminal How to install pandas from pip on windows cmd? 'ls' in CMD on Windows is not recognized Command to run a .bat file VMware Workstation and Device/Credential Guard are not compatible How do I kill the process currently using a port on localhost in Windows? how to run python files in windows command prompt?

Examples related to robocopy

How do I force Robocopy to overwrite files? Use Robocopy to copy only changed files? What is Robocopy's "restartable" option? How to exclude subdirectories in the destination while using /mir /xd switch in robocopy How to copy directories with spaces in the name Copy files without overwrite How can I make robocopy silent in the command line except for progress? How can I copy network files using Robocopy? How to copy a directory structure but only include certain files (using windows batch files)