How to Prevent Rsync from Creating Nested Directories When Syncing to Destination


14 views

When using rsync to transfer files between directories, you might encounter an unexpected behavior where rsync creates a nested directory structure. This typically happens when you specify both source and destination with directory names.

The command you're using:

rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests /var/www/tests

Results in files being copied to:

/var/www/tests/tests/

Rsync interprets this as "copy the contents of /var/www/tests on the remote server into a directory named 'tests' within /var/www/tests on the local machine." This is the default behavior when both source and destination explicitly include the directory name.

The most reliable way to prevent this is by using a trailing slash on the source path:

rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests/ /var/www/tests

Key differences:

  • /var/www/tests/ (with trailing slash) means "copy the contents of this directory"
  • /var/www/tests (without trailing slash) means "copy this directory itself"

If you prefer not to use trailing slashes, you can also try:

Method 1: Using the --no-implied-dirs flag

rsync -avzp --no-implied-dirs --del -e "ssh -p myport" user@hostname:/var/www/tests /var/www/

Method 2: Explicitly specifying the parent directory

rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests /var/www/

Here are some practical examples showing different scenarios:

Example 1: Sync remote directory contents to local directory

rsync -avz user@remote:/path/to/source/ /local/target/

Example 2: Sync specific files without directory recreation

rsync -avz user@remote:/path/to/files/*.txt /local/target/

Example 3: Preserving permissions without nested directories

rsync -avzp --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r user@remote:/source/ /target/
  • Mixing directory specifications (with/without trailing slashes) can lead to unexpected results
  • Using wildcards (*) without understanding how they interact with directory structures
  • Forgetting that rsync treats local and remote paths slightly differently

When dealing with large directories, the trailing slash method is generally more efficient because:

  • It avoids unnecessary directory creation checks
  • Reduces the number of stat() operations
  • Makes the transfer intention clearer to rsync

Many developers encounter this behavior when first using rsync for directory synchronization. The command:

rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests /var/www/tests

Creates an unexpected nested structure:

/var/www/tests/tests/

The root cause lies in how rsync interprets source paths:

  1. When the source path ends with a slash (/var/www/tests/), rsync copies the directory contents
  2. Without the trailing slash (/var/www/tests), rsync copies the directory itself

Here are three ways to achieve the desired behavior:

# Solution 1: Add trailing slash to source
rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests/ /var/www/tests

# Solution 2: Use proper destination path
rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests /var/www/

# Solution 3: Explicit content copy
rsync -avzp --del -e "ssh -p myport" user@hostname:/var/www/tests/* /var/www/tests/

When implementing this solution, you might want to exclude certain files:

rsync -avzp --del --exclude='*.log' -e "ssh -p 2222" \
user@example.com:/var/www/tests/ /var/www/tests

Other scenarios where directory nesting might occur:

  • Using relative paths without proper context
  • Mixing local and remote paths incorrectly
  • Forgetting to properly escape spaces in paths

Always test with --dry-run first to verify the expected directory structure:

rsync -avzn --del -e "ssh -p myport" user@hostname:/var/www/tests/ /var/www/tests