Don't overwrite permissions with tar file
Published by Nicholas Dunbar on February 9th, 2014
When you use tar to back-up a directory and then you want to restore that directory you may want to keep existing permissions intact. If you made changes to the permissions since the archive was created and you want to restore the original files while preserving the new permissions, here is a technique you can use. (This was tested on Red Hat Linux.)
This can be modified to run from a prompt by hard coding the variables into the lines starting with tar.
#CONFIGURATION---->
#set the name of the tar
path_to_tar=/some/dir/back-up.tar;
#if the root of the tar does not include the full path of the file and is instead a relative path you can set it here
target_dir=/some/dir/target/;
#<----CONFIGURATION
#back up permissions for files
echo "generating script containing back-up permissions";
tar -tvf $path_to_tar | awk -v p=$target_dir '{print p$6}' | grep -v -E "^.*/$" | xargs -I {} ls {} 2> /dev/null | tee 3; while read a; do echo chmod `stat -c '%a' "$a"` "$a"; echo chown `stat -c '%U:%G' "$a"` "$a"; done <3 | tee backed-up_perm.sh; rm 3;
tar -tvf $path_to_tar | awk -v p=$target_dir '{print p$6}' | grep -v -E "^.*/$" | xargs -I {} ls {} 2> /dev/null | tee 3; while read a; do echo chmod `stat -c '%a' "$a"` "$a"; echo chown `stat -c '%U:%G' "$a"` "$a"; done <3 | tee backed-up_perm.sh; rm 3;
#back up permissions for directories
tar -tvf $path_to_tar | awk -v p=$target_dir '{print p$6}' | grep -E "^.*/$" | xargs -I {} ls -d {} 2> /dev/null | tee 3; while read a; do echo chmod `stat -c '%a' "$a"` "$a"; echo chown `stat -c '%U:%G' "$a"` "$a"; done <3 | tee -a backed-up_perm.sh; rm 3;
Run the below when you want to restore the permissions.
#restore back-up
tar -cvf $path_to_tar $target_dir;
#restore permissions
echo "Running generated permissions file...";
sudo sh backed-up_perm.sh;
rm backed-up_perm.sh;
sudo sh backed-up_perm.sh;
rm backed-up_perm.sh;
echo "Permissions restored";
Example of running this from a prompt.
[local_username@localhost /]$ tar -tvf /some/dir/back-up.tar | awk '{print "/some/dir/target/"$6}' | grep -v -E "^.*/$" | xargs -I {} ls {} 2> /dev/null | tee 3; while read a; do echo chmod `stat -c '%a' "$a"` "$a"; sudo echo chown `stat -c '%U:%G' "$a"` "$a"; done <3 | tee backed-up_perm.sh; rm 3;
[local_username@localhost /]$ tar -tvf /some/dir/back-up.tar | awk -v '{print "/some/dir/target/"$6}' | grep -E "^.*/$" | xargs -I {} ls -d {} 2> /dev/null | tee 3; while read a; do echo chmod `stat -c '%a' "$a"` "$a"; sudo echo chown `stat -c '%U:%G' "$a"` "$a"; done <3 | tee -a backed-up_perm.sh; rm 3;
Explanation:
tar - archive program (like zip in windows)
-t - list of files
v - verbose output
f - define archive file name
/some/dir/back-up.tar - the name of the archive that the -f option requires
| - pipe output to next command
awk - a data formatting utility which has its own language interpreter
'{ - start awk language interpretation
"/some/dir/target" - awk hard coded string
$6 - 6th column of the output of each line that comes out of the tar command
}' - end awk language interpretation
| - pipe output to next command
grep - a utility for filtering lists of strings
-v - remove anything from the list that fits the criteria
-E - criteria of a regular expression
"^.*/$" - regular expression meaning any item of the list that ends in forward slash. In other words remove all directories from the list
| - pipe the output to the next command
xargs -I {} ls {} - run ls with the filename being equal to {} (this is here to remove files that exist in the tar but not in the target directory)
2> /dev/null - strip out any errors by sending them to /dev/null which deletes anything you send to it
| tee 3; - write the list of files to a temporary file called 3 with the command tee that simultaneously outputs to the screen as well.
while read a; - the end of this command is done <3 which reads in each line of the temporary file 3
do echo chmod `stat -c '%a' "$a"` "$a"; - print something like this chmod 770 some/file/name
echo chown `stat -c '%U:%G' "$a"` "$a"; - print something like chown user:group some/file/name
done <3 - end of the while loop that reads in each line of the temp file 3
| tee -a backed-up_perm.sh; - write all these generated chmod and chown commands to the file backed-up_perm.sh which is a shell script that can be ran to restore permissions.
rm 3; - remove the temp file called 3