4 October 2007

Directory synchronization batch file

Posted by Barnabas under: How To; Programming .

Batch IconToday I ran into a problem that required two directories to be synchronized. This is more than just copying all of the files from one directory to another, which XCOPY does very well. I had to ensure that there were no orphaned files in the destination that were not already in the source. The closest thing XCOPY comes to this is to copy only files that already exist in the destination. This can be a problem when deploying ASP.NET projects over and over, because “XCOPY deployment” does not account for deleted or renamed files.

There are many shareware GUI programs that can synchronize two directories like I wanted, but that seemed like overkill. I basically wanted a Windows version of rsync that would work out of the box (if you know of one, please share in the comments). I had already fired up the old source control editor and was about to code up a quick console program to do this when I realized that the same thing could be accomplished with a recursive batch file. Ten minutes later, I had this little script:

@echo off

if "%3"=="" (
echo Syncing %1 with %2
xcopy %1 %2 /d /i /y /s
)

for /D %%d in (%2\*) do (
if not exist "%1\%%~nd" (
echo Deleting directory %%~nd
rd "%%d" /s /q
)
)

for %%f in (%2\*) do (
if not exist "%1\%%~nf%%~xf" (
echo Deleting file %%~nf%%~xf
del "%%f"
)
)

for /D %%d in (%1\*) do call dir_sync.bat "%1\%%~nd" "%2\%%~nd" 0

Save this text as dir_sync.bat and remove the double-backslashes that Wordpress adds in. The command syntax is: dir_sync.bat “source directory” “destination directory”. Be sure to enclose the paths in quotation marks if there are any spaces.

If this command saves you ten minutes or spares you a pointless purchase, I’m happy to be able to pay it forward. If I just killed your shareware company, I’m really sorry.

5 Comments so far...

Mike Says:

7 October 2007 at 2:35 pm.

This script probably works just fine in most instances. You need to modify it for possible directories that have “.” in them. I have not tested it enough to see any other possible issues.

I used single backslashes where there were doubles, and input paths did not have the final backslash, but were in quotes to deal with spaces. You should of course test it before using it anywhere.

Did not quote full expressions %1 or %2, but started it after the number, otherwise double quotes at the beginning ended up negating the quotes for spaces.

Maybe some of these are not needed, but I could not get the script to work as above based on the directory structure that I was trying to duplicate from one server to the other. I hope I mentioned most of what I believe I has as an issue.

barnabas Says:

8 October 2007 at 8:54 pm.

Thanks for the suggestion Mike. I changed the search pattern in the second for loop from “%2\*.*” to “%2\*” and it seems to do the trick. If you find a better way to handle quotes and spaces, I’m all ears.

Scott Says:

27 May 2008 at 2:57 pm.

I know this is an old post, but I am using this code for a backup script and I’ve noticed that it still has problems with folders that have a dot in the name, and I can’t seem to figure out how to fix it. Here’s an example:
Source folder is called A, and contains another folder named “testfolder.a”
Destination is a folder called B.
If you run the script on that folder, this happens:

C:\Program Files\Scripts>dir_sync2.bat A B
Syncing A with B
A\testfolder.a\testfile1
A\testfolder.a\testfile2
2 File(s) copied
Deleting directory testfolder

Notice that everything after the dot in the folder name is missing. When it checks to see if the file exist, everything after the dot is removed, so it thinks the file does not exist and removes it. It looks to me like a problem with the Windows FOR command. Do you know of a workaround/fix for this?

Jesse Chisholm Says:

23 June 2008 at 7:20 pm.

The answer is to do for directories what you did for files. In the files loop you used both the file name %%~nf and the file extension %%~xf to make the entire file’s basename: %%~nf%%~xf

Do the same in your directory loop. Use %%~nd%%~xd to get the entire basename of the directory.

BTW. nice recursive batch file.

-Jesse

Jesse Chisholm Says:

23 June 2008 at 7:50 pm.

PS: You may want to add this near the top as a parameter validation step:

for %%I in (%1 %2) do (
if not exist “%%~I” (
echo Can’t find %%~I
goto _exit
)
)

And, of course, the :_exit label at the bottom.

-Jesse

Leave a Reply

Categories

Archives

Links

Meta