It's sometimes necessary to copy a directory tree from one place to another, preserving the directory structure, while not copying the contents of the directories themselves. This is actually fairly easy to do with rsync. We're going to go through an example of copying the 'src' directory into 'dst'. Because we would like to test this first to make sure it will work, we'll take advantage of rsync's dry-run feature. Here is the command:
rsync -av -n --include='*/' --exclude='*' src/ dst
And here is the source directory tree, with a few files thrown in for good measure:
dmaxwell@serenity:~/tmp$ ls -R src src/bar: src/baz: sitemap_gen.pl sitemap.xml ssl_error.png test1.png test2.png src/foo: src/quux: blarg.png bookmarks_3_1_12.html cap1_inside.pcap cap3.pcap config.xml example_urllist.txt fg.png test src/quux/test: README
Now for the options:
- -av: The -a option turns on rsync's archive mode, basically making an exact copy of what it finds, recursively, even preserving timestamps (equivalent to -rlptgoD if you want to read up on the rsync options). As you might guess, -v means 'verbose', and will cause rsync to print each file or directory it copies, along with any errors and a summary of how many bytes were transferred.
- -n: This is the dry-run option. Combined with -v, this causes rsync to display what it would do had you not used -n.
- --include='*/': Matches and includes all directories.
- --exclude='*': Matches and excludes everything
The order of the include and exclude options is important, since for any given file path, the first matching pattern is used. That means that if you put the include after the exclude, nothing will be matched by the include (in this case resulting in an empty copy). Also be aware that the trailing slash on the src/ argument is necessary. If we omit it, the src directory itself is copied into dst, rather than the contents of src. An important but subtle distinction. Now here is our dry-run:
dmaxwell@serenity:~/tmp$ rsync -av -n --include='*/' --exclude='*' src/ dst sending incremental file list created directory dst ./ bar/ baz/ foo/ quux/ quux/test/ sent 152 bytes received 35 bytes 374.00 bytes/sec total size is 0 speedup is 0.00 (DRY RUN)
We can see that rsync is just copying directories, and it's safe to run the command without the -n:
dmaxwell@serenity:~/tmp$ rsync -av --include='*/' --exclude='*' src/ dst sending incremental file list created directory dst ./ bar/ baz/ foo/ quux/ quux/test/ sent 152 bytes received 35 bytes 374.00 bytes/sec total size is 0 speedup is 0.00 dmaxwell@serenity:~/tmp$ ls -R dst dst: bar baz foo quux dst/bar: dst/baz: dst/foo: dst/quux: test dst/quux/test:
There we have it - we successfully copied the directory structure from src/ into dst/, without copying any files. Rsync is an amazing tool and I'll have more to say on it in the future.