Is there a command or flag to clone the user/group ownership and permissions on a file from another file? To make the perms and ownership exactly those of another file?
-
Related questions: https://askubuntu.com/questions/56792/how-to-copy-only-file-attributes-metadata-without-actual-content-of-the-file/143092 and https://unix.stackexchange.com/questions/44253/how-to-clone-copy-all-file-directory-attributes-onto-different-file-directory – Sohail Si Jan 27 '22 at 16:47
8 Answers
On GNU/Linux chown and chmod have a --reference option
chown --reference=otherfile thisfile
chmod --reference=otherfile thisfile
- 50,671
- 14
- 120
- 105
-
1Could you reference to this answer (and likely cite it) as answer to my question : http://unix.stackexchange.com/questions/44253/how-to-clone-copy-all-directory-attributes-permission-ownership-times-exte ? , I think I will be great addition and I'd love to find up-votes there for it. – Grzegorz Wierzowiecki Jul 31 '12 at 20:40
-
@GrzegorzWierzowiecki: probably that question should be closed, but is a little bit different than this and already has answers, so I better do nothing. – enzotib Jul 31 '12 at 20:54
-
As you wish and suggest. Thanks for help, I have never put attention to `--reference` parameter of `chmod` and `chown` before :). – Grzegorz Wierzowiecki Jul 31 '12 at 22:02
On any unix with GNU utilities, such as (non-embedded) Linux or Cygwin, you can use chmod --reference and chown --reference.
If your system has ACLs, try the ACL commands getfacl and setfacl. These commands differ a little from system to system, but on many you can use getfacl other_file | setfacl -bnM - file_to_change to copy the permissions. This doesn't copy the ownership; you can do that with careful parsing of ls -l other_file, assuming that you don't have user or group names containing whitespace.
LC_ALL=C ls -l other_file | {
read -r permissions links user group stuff;
chown -- "$user:$group" file_to_change
}
getfacl other_file | setfacl -bnM - file_to_change
- 807,993
- 194
- 1,674
- 2,175
-
1You should have ACL installed and filesystem mounted with ACL enabled. – enzotib Sep 14 '11 at 04:03
-
2@enzotib At least on Linux, ACL tools will work to copy permissions (but not ownership) even if the source and target filesystem don't support ACLs. – Gilles 'SO- stop being evil' Sep 14 '11 at 06:57
-
Pour info, on RHEL 7 (and possibly onwards) you can use `getfacl other_file | setfacl --set-file=- file_to_change`. – dr_ Mar 29 '23 at 14:01
Did a bash command based on the response of Matteo :)
Code:
chmod $( stat -f '%p' "$1" ) "${@:2}"
Usage:
cp-permissions <from> <to>...
- 201
- 2
- 5
-
7Egad! Where did you learn to say `${*:2}`? Don't ever do that again! That will fail if any of the filenames contain space (or tabs). Use `"${@:2}"`. Also, use `"$1"` instead of just `$1`. – G-Man Says 'Reinstate Monica' May 26 '15 at 04:10
-
`chmod "$(stat -c '%a' "$fromfile")" tofile` in GNU Coreutils, but you might as well use `--reference` in that case since the`stat` CLI utility is not POSIX, it even says http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.htmlthat `ls -l` won't cut it: "The output of ls (with the -l and related options) contains information that logically could be used by utilities such as chmod and touch to restore files to a known state. However, this information is presented in a format that cannot be used directly by those utilities or be easily translated into a format that can be used." – Ciro Santilli OurBigBook.com Sep 02 '18 at 12:10
If you are not using a system with GNU's chmod/chown (which support the --reference option) you could try to parse the output of ls -l
Here a small script for chmod (if you have a see which supports extended regexes they could be written in a much more readable way ...)
#!/bin/sh
reference=$1
shift
files=$*
# strip the permissions (whith extended regexes could be more readable)
OWNER=$(ls -l ${reference} | sed -e "s/.\(...\).*/\1/" | sed -e "s/[-]//g" )
GROUP=$(ls -l ${reference} | sed -e "s/....\(...\).*/\1/" | sed -e "s/[-]//g" )
OTHER=$(ls -l ${reference} | sed -e "s/.......\(...\).*/\1/" | sed -e "s/[-]//g" )
chmod u=${OWNER},g=${GROUP},o=${OTHER} ${files}
UPDATE:
This is even easier using stat:
chmod $( stat -f '%p' ${reference} ) ${files}
- 9,676
- 4
- 49
- 66
-
2Instead of parsing `ls -l` output, you could you could parse `stat`output. – jfg956 Sep 21 '11 at 19:51
-
@jfgagne: thanks makes sense I do not know why I didn't think about it in the first place. I updated the answer – Matteo Sep 22 '11 at 05:28
-
2You're using *BSD `stat` syntax here. Your `chmod $(stat ...)` command won't work because `%p` alone outputs too much information for *BSD's `chmod`, use `%Lp` to output just the u/g/o bits. Something slightly more elaborate would be required for sticky/setuid/setgid bits. – mr.spuratic Jun 07 '13 at 10:17
This works for me:
cp -p --attributes-only <from> <to>
- 31
- 1
-
1That copies *all* attributes though (change `-p` to `--preserve=ownership,mode` to copy only permissions and ownership (and ACLs if any)). That will also not work for files of type *directory*. Also note that if `
` is a symlink, that will copy the attributes to the target of the symlink (likely what one would want anyway as permissions of symlinks themselves are rarely relevant (though ownership can be)). – Stéphane Chazelas Jan 27 '22 at 16:46
On MacOS, cp --attributes-only or chmod --reference won't work.
A solution for MacOS is to first install coreutils using
brew install coreutils
then use the coreutils's version of cp command, that is gcp:
gcp --attributes-only --archive sourcefile destfile
This will copy the ownership and attributes while preserving destfile's content and filename.
- 27,586
- 56
- 179
- 309
- 151
- 4
-
note that `--archive` works recursively, which is not necessarily what one may want. – SpinUp __ A Davis Sep 02 '22 at 17:19
I wanted to add an adjustment to Matteo's script. A for loop should be used to validate that the files exist before actually running the chmod command on them. This will let the script error out more gracefully.
I think this is the best option because it can be used for all *nix OSes, like Solaris, Linux, etc.
#!/bin/sh
reference=$1
shift
files=$*
for file in $reference $files; do
[ -f $file ] || { echo "$file does not exist"; exit 1; }
done
# strip the permissions (whith extended regexes could be more readable)
OWNER=$(ls -l ${reference} | sed -e "s/.\(...\).*/\1/" | sed -e "s/[-]//g" )
GROUP=$(ls -l ${reference} | sed -e "s/....\(...\).*/\1/" | sed -e "s/[-]//g" )
OTHER=$(ls -l ${reference} | sed -e "s/.......\(...\).*/\1/" | sed -e "s/[-]//g" )
chmod u=${OWNER},g=${GROUP},o=${OTHER} ${files}
I found that on one of my Solaris 10 machines, stat was not found. That might be an issue with my configuration though.
-
[Why *not* parse `ls` (and what to do instead)?](https://unix.stackexchange.com/q/128985/126755) | -1 – Vlastimil Burián Jan 27 '22 at 17:57
I got inspired by @Matteo and @mjlescano. This one-liner works on MacOS without installing any additional dependencies.
permcp() { chmod $( stat -f '%A' "$1" ) "${@:2}" } && permcp sourcefile targetfile
We have just defined a function and called the function with source and target file parameters. You can use the "permcp" function for subsequent invocations if it's required.
- 99
- 1
- 2