Synchronize two folders under Windows with robocopy.
Additional features:
- Optional: If a file, which exists in the target directory, is changed in source directory, then its older version in the target directory will be backed up before it is replaced.
- Two-way syncing:
- Any file in the target directory that don't exist in the source directory, will be backed up before it is deleted. A timestamp wil be added to the name of each file that has been backed up.
- Any empty folders are deleted during the sync process.
syncFolders.bat source_folder target_folder
The following settings can be configured in the script:
VERBOSE
If this is set to true, then DEBUG logging is enabled (default: false).
BIN
Files in target_folder, which do not exists source_folder, will be moved to BIN before deleting them in target_folder (default: bin). If this directory does not exists, then the script creates it during runtime.
ARCHIVE
Directory to save older version of updated files (default: archive). If this directory does not exists, then the script creates it during runtime.
BACKUP
If this is set to true, then files in target_folder will be copied to ARCHIVE before they will be replaced by newer version in source_folder.
PATH_PATTERNS_IN
File with patterns, separated by newline.
# Example for patterns_in.txt
*.cfg
*.bak
Only files which match these patterns will be copied from source_folder to target_folder.
PATH_PATTERNS_EX
File with patterns, separated by newline.
# Example for patterns_ex.txt
*_template
Files which match these patterns will not be copied from source_folder to target_folder.
@REM Validate if user passed enough parameters
if "%1"=="" (
echo Usage: %~nx0 source_folder target_folder
exit /b 1
)
if "%2"=="" (
echo Error: Missing second parameter.
echo Usage: %~nx0 source_folder target_folder
exit /b 1
)
%~nx0 is a parameter extension for filenames which expands %0 to a file name and extension only (refer to https://ss64.com/nt/syntax-args.html)
%~n0 expands %0 only to file name.
@REM Set timestamp
set hh=%TIME:~0,2%
@REM To prevent syntax error during file operations due to whitespaces, a null is appended if the part of TIME is lower than 10.
if "%hh:~0,1%" == " " set hh=0%hh:~1,1%
set mm=%TIME:~0,2%
if "%mm:~0,1%" == " " set mm=0%mm:~1,1%
set ss=%TIME:~0,2%
if "%ss:~0,1%" == " " set ss=0%ss:~1,1%
set DD=%date:~0,2%
set MM=%date:~3,2%
set YYYY=%date:~6,4%
set dtime=%YYYY%%MM%%DD%_%hh%%mm%%ss%
%DATE%contains current date, e.g. 15.05.25%VAR:~n,m%extracts m strings from VAR, beginning from n including n.%TIME%contains the current time in the local format, e. g. 9:23:10,76if "%hh:~0,1%" == " " set hh=0%hh:~1,1
If hour, min etc. is lower than 10, its output with a whitespace e. g. _9 . To prevent syntax error during file operations, the whitespace is replaced by a null.
@REM Basic checks
if not exist %SOURCE_DIR% (
echo %SOURCE_DIR% does not exists. Abort script.
exit /b
)
if not exist %DST_DIR% (
echo %DST_DIR% does not exists. Abort script.
exit /b
)
exitwith/bexits the current script, but not the command shell (refer to https://ss64.com/nt/exit.html)
setlocal enabledelayedexpansion
set filters=
@REM Get patterns for sync
for /F %%F in ('type %PATH_PATTERNS_IN%') do (
set "pat=%%F"
set "in_patterns=!in_patterns!!pat! "
)
setlocal enabledelayedexpansion: Delayed Expansion is necessary for adding values in a variable (refer to https://ss64.com/nt/delayedexpansion.html)- The loop iterates through each line in file, stores each value in
patand appends value ofpatinin_patterns. typeis likecat- Result:
in_patterns= e.g.*.bat *.cfg
To execute the loop above directly in the Shell, %%F has to be replaced by %F.
@REM Delete empty folders in target dir
robocopy %DST_DIR% %DST_DIR% /S /MOVE
/Sskips empty folders/MOVE: Moves files and directories, and deletes them from the source after they're copied.
robocopy %SOURCE_DIR% %DST_DIR% %in_patterns% /MT:32 /LOG+:%LOGFILE% /NDL /NJS /NS /NP /DCOPY:T /S /XF %ex_patterns%
/DCOPY:T- Preserve timestamps/XF- Exclude files based on patterns/S- Copy subdirectories, except of emtpy ones/LOG:+redirects output in logfile and appends (+) entries in logfile./NLD: Directory names aren't logged./NJS: No job summary in log./NS: File sizes aren't logged./NP: No log of progress./MT:32: To speed up runtime, create multi-threaded copies with 32 threads (default 8)- Source: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/robocopy
for /R %DST_DIR% %%F in (*.*) do (
set "dst_path=%%~F"
set "src_path=!dst_path:%DST_DIRNAME%=%SRC_DIRNAME%!"
if not exist !src_path! (
move "%%F" %BIN%\%dtime%_%%~nxF
)
)
- Walks recursively through destination directory and checks, if file exists in source directory.
for /R %DST_DIR% %%F in (*.*)loops through all files (*.*) recursively in the%DST_DIR%directory.%%Frepresents the full path of each file found.dst_path=%%~Fstores the fullpath (%%~F) in the variabledst_path.!dst_path:%DST_DIR%=%SRC_DIR%!replaces name of target folder by name of source folder in path of file in target folder.
Example
-
DST_DIR= C:\Users\user\Skripte\syncConf\testdata\test_target\ -
SRC_DIR= C:\Users\user\Skripte\syncConf\testdata\test_glx\ -
SRC_DIRNAME= test_glx -
DST_DIRNAME= test_target -
dst_path= C:\Users\user\Skripte\syncConf\testdata\test_target\wildfly\test.cfg -
src_path→ C:\Users\user\Skripte\syncConf\testdata\test_glx\wildfly\test.cfg -
!src_path!is a delayed expansion
What is delayed expansion?
Delayed expansion is a feature in batch scripting to safely use and update variables inside loops or conditional blocks (like for, if, etc.) where normal variable expansion like %VAR% would not work as expected.
If a variable changes inside a loop or block, %VAR% will still have the old value (or no value) from before the loop started.
If file does not exists in source directory, it will be moved to the bin directory.
Why /MIR is not used?
To mirror both directories respectively deleting files / folders which do not exist in source folder, do not use /mir in relation with filters
robocopy %SOURCE_DIR% %DST_DIR% /S /MIR /DCOPY:T /MIR /DCOPY:T deletes files in destination dir which do not exists in source dir
robocopy %SOURCE_DIR% %DST_DIR% /S /MIR "*.cfg" "*.bak" /DCOPY:T /MIR /DCOPY:T does not delete files in destination dir which do not exists in source dir.