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


3 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