When managing Linux systems or deploying applications, verifying consistent file permissions and ownership between directories is crucial. This becomes especially important when:
- Migrating data between servers
- Synchronizing development and production environments
- Troubleshooting permission-related issues
- Auditing security configurations
The ls
command with appropriate flags provides the foundation:
ls -laR /path/to/directory | grep -v "^total"
For more targeted output:
ls -ln /path | awk '{print $1,$3,$4,$9}'
Here's a Bash script that recursively compares permissions and ownership:
#!/bin/bash
compare_dirs() {
dir1=$1
dir2=$2
# Create temporary files
tmp1=$(mktemp)
tmp2=$(mktemp)
# Collect permission data
find "$dir1" -printf "%M %u %g %p\n" | sort > "$tmp1"
find "$dir2" -printf "%M %u %g %p\n" | sort > "$tmp2"
# Compare and highlight differences
diff -y --suppress-common-lines "$tmp1" "$tmp2"
# Cleanup
rm "$tmp1" "$tmp2"
}
# Usage example
compare_dirs "/path/to/first/dir" "/path/to/second/dir"
For enterprise use cases, consider:
1. Using rsync with dry-run:
rsync -n -a -i --dry-run /source/ /destination/
2. Metamorphosis (meta-data comparison tool):
metamorphosis compare --permissions --ownership dir1 dir2
For complex directory structures, generate a visual report:
#!/bin/bash
generate_report() {
dir=$1
report_file=$2
echo "Permission Report for: $dir" > "$report_file"
echo "Generated: $(date)" >> "$report_file"
echo "---------------------------------" >> "$report_file"
find "$dir" -printf "%M\t%u\t%g\t%p\n" | \
awk 'BEGIN {print "Perms\tOwner\tGroup\tPath"}
{print $0}' >> "$report_file"
}
generate_report "/path/to/dir" "permission_report.txt"
Case 1: Web server directory synchronization
diff <(find /var/www/html -printf "%M %u %g %p\n") \
<(find /backup/www -printf "%M %u %g %p\n")
Case 2: Configuration management verification
#!/bin/bash
# Verify /etc permissions match golden image
GOLDEN_DIR="/opt/golden_configs"
LIVE_DIR="/etc"
for file in $(find $GOLDEN_DIR -type f); do
rel_path=${file#$GOLDEN_DIR}
live_file="$LIVE_DIR$rel_path"
if [ -e "$live_file" ]; then
golden_perms=$(stat -c "%a" "$file")
live_perms=$(stat -c "%a" "$live_file")
if [ "$golden_perms" != "$live_perms" ]; then
echo "Mismatch: $rel_path (Golden: $golden_perms, Live: $live_perms)"
fi
fi
done
When managing servers or deploying applications, you'll often need to verify that directory structures maintain consistent permissions and ownership. While diff
excels at content comparison, it doesn't handle metadata differences. Here's how to tackle this common sysadmin challenge.
The most flexible approach combines find
with stat
to generate comparable output:
#!/bin/bash
# Compare permissions between dir1 and dir2
compare_perms() {
local dir1=$1
local dir2=$2
# Generate permission reports
find "$dir1" -printf "%M %u %g %p\n" | sort > /tmp/dir1_perms.txt
find "$dir2" -printf "%M %u %g %p\n" | sort > /tmp/dir2_perms.txt
# Diff the outputs
diff -y --suppress-common-lines /tmp/dir1_perms.txt /tmp/dir2_perms.txt
}
compare_perms "/path/to/first/dir" "/path/to/second/dir"
For a dry-run comparison without actual transfer:
rsync -n -av --dry-run --info=NAME,STATS,FLIST \
--itemize-changes "/source/" "/destination/" | grep -E "^[.](...){3}"
This outputs permission changes (.f.....
), owner changes (.....o.
), and group changes (......g
).
For more sophisticated needs, consider this Python script:
import os
import sys
from collections import defaultdict
def get_permissions(root):
permissions = defaultdict(dict)
for dirpath, dirnames, filenames in os.walk(root):
for name in dirnames + filenames:
path = os.path.join(dirpath, name)
stat = os.stat(path)
permissions[path] = {
'mode': stat.st_mode,
'uid': stat.st_uid,
'gid': stat.st_gid
}
return permissions
def compare_dirs(dir1, dir2):
perms1 = get_permissions(dir1)
perms2 = get_permissions(dir2)
all_paths = set(perms1.keys()).union(set(perms2.keys()))
for path in sorted(all_paths):
data1 = perms1.get(path)
data2 = perms2.get(path)
if not data1:
print(f"Only in {dir2}: {path}")
continue
if not data2:
print(f"Only in {dir1}: {path}")
continue
if data1['mode'] != data2['mode']:
print(f"Permission mismatch: {path}")
print(f" {dir1}: {oct(data1['mode'])[-4:]}")
print(f" {dir2}: {oct(data2['mode'])[-4:]}")
if data1['uid'] != data2['uid']:
print(f"Owner mismatch: {path}")
if data1['gid'] != data2['gid']:
print(f"Group mismatch: {path}")
if __name__ == "__main__":
compare_dirs(sys.argv[1], sys.argv[2])
For enterprise environments, consider these alternatives:
- tree:
tree -ugp /path
shows permissions in tree format - git: Track permission changes in version control with
git config core.filemode true
- auditd: For continuous monitoring of permission changes
Add -L
to find
commands to follow symlinks, or use this modified stat approach:
find -L /path -exec stat -c "%a %U %G %n" {} +