When copying files in Linux using the cp
command, the default behavior creates new permissions on the destination file based on the umask settings. This often becomes problematic when you need to maintain the existing permissions of the target file while updating its content.
The normal cp
command operation:
cp /source/file /destination/existing_file
This will overwrite the destination file's content AND change its permissions to match the source file.
The most effective solution is to combine --no-preserve=mode
with cp
:
cp --no-preserve=mode /tmp/file /home/file
This tells cp to copy the content but not modify the mode (permissions) of the destination file.
Another method that completely avoids cp's permission handling:
cat /tmp/file > /home/file
This preserves all original permissions since it's just writing content to an existing file.
Where this technique matters most:
- Updating configuration files that require specific permissions
- Maintaining web server file permissions during deployments
- System administration tasks where permission consistency is critical
If you need more granular control:
cp --no-preserve=all --preserve=timestamps /src/file /dest/file
This preserves the destination's permissions while copying timestamps from source.
Important notes about behavior:
- Directory permissions behave differently than files
- Root user operations may bypass some permission rules
- SELinux contexts add another layer of complexity
For most cases, this is the optimal command:
cp --no-preserve=mode --preserve=ownership /source /destination
It provides the best balance between content copying and permission preservation.
When copying files in Unix/Linux systems using the cp
command, the default behavior creates new files with the permissions of the source file while ignoring the destination file's existing permissions. This becomes problematic when you need to maintain specific ownership (chown
) and group (chgrp
) settings on the destination file.
The most straightforward solution is to use the --no-preserve=mode
option:
cp --no-preserve=mode /tmp/file /home/file
This tells cp
not to preserve the source file's mode (permissions), allowing the destination file to keep its original permissions while updating the content.
1. Using install Command
The install
command provides more control over file attributes:
install -p -m $(stat -c %a /home/file) /tmp/file /home/file
2. Combining cp and chmod
Copy first, then restore permissions:
cp /tmp/file /home/file
chmod $(stat -c %a /home/file.old) /home/file
3. Using rsync with --chmod
For more complex scenarios, rsync
offers granular control:
rsync -av --chmod=ugo=rw /tmp/file /home/file
If you also need to preserve ownership (user and group), use:
cp --no-preserve=mode --preserve=ownership /tmp/file /home/file
Consider a scenario where you need to update website files without changing their permissions:
#!/bin/bash
SRC="/var/www/staging/index.html"
DEST="/var/www/production/index.html"
# Preserve destination permissions
OLD_PERMS=$(stat -c %a "$DEST")
cp --no-preserve=mode "$SRC" "$DEST"
chmod $OLD_PERMS "$DEST"
The key options for permission handling in cp
:
--preserve=[ATTR_LIST]
: Preserve specified attributes (mode,ownership,timestamps)--no-preserve=[ATTR_LIST]
: Don't preserve specified attributes-p
: Same as--preserve=mode,ownership,timestamps
When writing scripts that modify production files:
- Always check current permissions before copying
- Consider using
install
for more predictable behavior - Test permission changes in staging first
- Document permission requirements in your deployment procedures