When maintaining multiple environments or doing data migrations, we often encounter identical directory structures where only the permissions need to be synchronized. This commonly occurs in:
- Staging to production deployments
- Backup restoration scenarios
- Continuous integration setups
The most efficient method uses rsync
's permission preservation features:
rsync -av --perms --dry-run /source/path/ /destination/path/
Remove --dry-run
when ready to execute. The flags:
-a
: Archive mode (recursive copy)-v
: Verbose output--perms
: Preserve permissions
For more control, combine find
and chmod
:
cd /source/path find . -type d -exec chmod --reference={} /destination/path/{} \; find . -type f -exec chmod --reference={} /destination/path/{} \;
When dealing with symbolic links or special permissions:
rsync -av --perms --links --specials --dry-run /source/path/ /destination/path/
To validate permission synchronization:
diff -r <(cd /source/path; find . -printf "%m %p\n" | sort) \ <(cd /destination/path; find . -printf "%m %p\n" | sort)
For regular synchronization, create a bash script:
#!/bin/bash SOURCE_DIR="/path/to/source" DEST_DIR="/path/to/destination" if [ ! -d "$SOURCE_DIR" ] || [ ! -d "$DEST_DIR" ]; then echo "Error: Directories don't exist" >&2 exit 1 fi rsync -av --perms --links --specials "$SOURCE_DIR"/ "$DEST_DIR"/
When working with mirrored directory structures in Linux/Unix systems, maintaining consistent permissions across different versions of the same file tree can be crucial for security and functionality. The scenario involves:
- Source Tree: Directory structure with correct permissions (mode bits)
- Target Tree: Identical directory structure (same paths/filenames) but with wrong permissions
The most efficient method combines find
with chmod
through command substitution:
find /path/to/source -type d -exec sh -c 'chmod --reference="{}" "/path/to/target/{}"' \;
find /path/to/source -type f -exec sh -c 'chmod --reference="{}" "/path/to/target/{}"' \;
For a robust solution that handles edge cases:
#!/bin/bash
SRC="/path/to/source"
DST="/path/to/target"
# Verify directory existence
if [ ! -d "$SRC" ] || [ ! -d "$DST" ]; then
echo "Error: Source or target directory does not exist" >&2
exit 1
fi
# Process directories first
find "$SRC" -type d | while read -r dir; do
rel_path="${dir#$SRC}"
target_dir="$DST$rel_path"
if [ -d "$target_dir" ]; then
chmod --reference="$dir" "$target_dir"
fi
done
# Then process files
find "$SRC" -type f | while read -r file; do
rel_path="${file#$SRC}"
target_file="$DST$rel_path"
if [ -f "$target_file" ]; then
chmod --reference="$file" "$target_file"
fi
done
Using rsync
For large directory trees, rsync can be more efficient:
rsync -a --no-owner --no-group --chmod=ugo=rwX /path/to/source/ /path/to/target/
Preserving ACLs
If extended attributes matter, use getfacl/setfacl:
getfacl -R /path/to/source > permissions.acl
setfacl --restore=permissions.acl
- Always test with
-exec echo
first to verify paths - Consider using
sudo
for system directories - Check for symlinks with
-L
if needed - For SELinux contexts, add
chcon --reference
For massive directory trees, this parallel approach can help:
find /path/to/source -print0 | parallel -0 -j8 chmod --reference={} /path/to/target/{}