Search site

Add to Google Subscribe in NewsGator Online

Featured Articles
Directory copy in Unix back

Dollysheep

In most flavours of Unix, the command cp is used to copy one file to another, and cp -R is used to copy the whole directory hierarchy. For example, let's say we want to make a copy of the directory /home/pcguest/htdocs into /home/httpd/htdocs, and the source directory has the contents:

[pcguest@localhost /home/pcguest]$ ls -lrt htdocs/*
-rw-r--r-- 1 pcguest pcguest 6393 Mar 25 00:25 htdocs/index.html

htdocs/javascript:
total 8
-rw-r--r-- 1 pcguest pcguest 5752 Mar 25 00:26 transcraft.js

htdocs/stylesheet:
total 4
-rw-r--r-- 1 pcguest pcguest 1401 Mar 25 00:27 stylesheet.css

htdocs/images:
total 36
-rw-r--r-- 1 pcguest pcguest 715 Mar 25 00:24 topright.jpg
-rw-r--r-- 1 pcguest pcguest 716 Mar 25 00:24 topleft.jpg
-rw-r--r-- 1 pcguest pcguest 2705 Mar 25 00:24 logo.jpg
-rw-r--r-- 1 pcguest pcguest 925 Mar 25 00:24 button.jpg
-rw-r--r-- 1 pcguest pcguest 1327 Mar 25 00:24 button1.jpg
-rw-r--r-- 1 pcguest pcguest 713 Mar 25 00:24 bottomright.jpg
-rw-r--r-- 1 pcguest pcguest 707 Mar 25 00:24 bottomleft.jpg
-rw-r--r-- 1 pcguest pcguest 1603 Mar 25 00:24 bg.jpg
-rw-r--r-- 1 pcguest pcguest 3500 Mar 25 00:24 bgbottom.jpg

then the command is:

[httpd@locahost /home/pcguest]$ cp -R htdocs /home/httpd

which yields:

[httpd@localhost /home/pcguest]$ ls -lrt /home/httpd/htdocs/*
-rw-r--r-- 1 httpd httpd 6393 Mar 25 00:35 htdocs2/index.html

htdocs2/stylesheet:
total 4
-rw-r--r-- 1 httpd httpd 1401 Mar 25 00:35 stylesheet.css

htdocs2/javascript:
total 8
-rw-r--r-- 1 httpd httpd 5752 Mar 25 00:35 transcraft.js

htdocs2/images:
total 36
-rw-r--r-- 1 httpd httpd 715 Mar 25 00:35 topright.jpg
-rw-r--r-- 1 httpd httpd 716 Mar 25 00:35 topleft.jpg
-rw-r--r-- 1 httpd httpd 2705 Mar 25 00:35 logo.jpg
-rw-r--r-- 1 httpd httpd 925 Mar 25 00:35 button.jpg
-rw-r--r-- 1 httpd httpd 1327 Mar 25 00:35 button1.jpg
-rw-r--r-- 1 httpd httpd 713 Mar 25 00:35 bottomright.jpg
-rw-r--r-- 1 httpd httpd 707 Mar 25 00:35 bottomleft.jpg
-rw-r--r-- 1 httpd httpd 1603 Mar 25 00:35 bg.jpg
-rw-r--r-- 1 httpd httpd 3500 Mar 25 00:35 bgbottom.jpg

OK, we can immediately notice two problems here. The first problem is the ownership of the destination directory's contents is now completely transferred to httpd. This might be what you want, it might not be, but it should be noted. The second problem is the timestamp of all the files within the destination directory is now set to the same value of 00:35, which is not very convenient if you have scripts which detect changes in file timestamps (like rsync, for example).

So is there a way of preserving the timestamps of the contents in the source directory in the process of copying ? Well, there are ways, of course. The most obvious way is to zip up the contents and then unzip them in the destination. However, as we are using Unix, which is famed for its command line capability, there is a much easier way of doing this. We need the help of the pipe in order to do this:

[httpd@localhost /home/pcguest]$ tar cvf - htdocs|(cd /home/httpd;tar xvf -)
htdocs/
htdocs/images/
htdocs/images/bg.jpg
htdocs/images/bgbottom.jpg
htdocs/images/bottomleft.jpg
htdocs/images/bottomright.jpg
htdocs/images/button.jpg
htdocs/images/button1.jpg
htdocs/images/logo.jpg
htdocs/images/topleft.jpg
htdocs/images/topright.jpg

[httpd@localhost /home/httpd]$ ls -lrt htdocs/*
-rw-r--r-- 1 httpd httpd 6393 Mar 25 00:25 htdocs/index.html

htdocs/javascript:
total 8
-rw-r--r-- 1 httpd httpd 5752 Mar 25 00:26 transcraft.js

htdocs/stylesheet:
total 4
-rw-r--r-- 1 httpd httpd 1401 Mar 25 00:27 stylesheet.css

htdocs/images:
total 36
-rw-r--r-- 1 httpd httpd 715 Mar 25 00:24 topright.jpg
-rw-r--r-- 1 httpd httpd 716 Mar 25 00:24 topleft.jpg
-rw-r--r-- 1 httpd httpd 2705 Mar 25 00:24 logo.jpg
-rw-r--r-- 1 httpd httpd 925 Mar 25 00:24 button.jpg
-rw-r--r-- 1 httpd httpd 1327 Mar 25 00:24 button1.jpg
-rw-r--r-- 1 httpd httpd 713 Mar 25 00:24 bottomright.jpg
-rw-r--r-- 1 httpd httpd 707 Mar 25 00:24 bottomleft.jpg
-rw-r--r-- 1 httpd httpd 1603 Mar 25 00:24 bg.jpg
-rw-r--r-- 1 httpd httpd 3500 Mar 25 00:24 bgbottom.jpg

As you can see, the timestamps have been preserved in the process, and instead of using the cp command, we use the tar command instead. What the command is essentially saying is put the contents of my htdocs directory into a tar file, but instead of the file being a physical disk file, just stream it to standard out instead. standard out in this case happens to be a pipe, and the other end of the pipe is the reverse process, which duly untars the contents back to their original relative paths by reading from standard in. The trick is the process which performs the untar is executed in a subshell, and is preceded with a chdir command, causing the contents to be unpacked into the destination directory instead of the original source directory. The main characteristic of tar is to preserve the ownership, permissions, and timestamps of all files as part of the archiving process.

The next question we will be asking is, well it does not look like the ownership has been preserved, as all the files are now owned by httpd instead of pcguest. The reason for this is because in Unix, only the root user is capable of changing ownership of files and directories. This being the case, if the id you are using happens to have sudo privilege, you can modify the above command slightly to achieve the desired result:

[httpd@localhost /home/pcguest]$ tar cvf - htdocs|(cd /home/httpd;sudo tar xvf -)
htdocs/
htdocs/images/
htdocs/images/bg.jpg
htdocs/images/bgbottom.jpg
htdocs/images/bottomleft.jpg
htdocs/images/bottomright.jpg
htdocs/images/button.jpg
htdocs/images/button1.jpg
htdocs/images/logo.jpg
htdocs/images/topleft.jpg
htdocs/images/topright.jpg

[httpd@localhost /home/httpd]$ ls -lrt htdocs/*
-rw-r--r-- 1 pcguest pcguest 6393 Mar 25 00:25 htdocs/index.html

htdocs/javascript:
total 8
-rw-r--r-- 1 pcguest pcguest 5752 Mar 25 00:26 transcraft.js

htdocs/stylesheet:
total 4
-rw-r--r-- 1 pcguest pcguest 1401 Mar 25 00:27 stylesheet.css

htdocs/images:
total 36
-rw-r--r-- 1 pcguest pcguest 715 Mar 25 00:24 topright.jpg
-rw-r--r-- 1 pcguest pcguest 716 Mar 25 00:24 topleft.jpg
-rw-r--r-- 1 pcguest pcguest 2705 Mar 25 00:24 logo.jpg
-rw-r--r-- 1 pcguest pcguest 925 Mar 25 00:24 button.jpg
-rw-r--r-- 1 pcguest pcguest 1327 Mar 25 00:24 button1.jpg
-rw-r--r-- 1 pcguest pcguest 713 Mar 25 00:24 bottomright.jpg
-rw-r--r-- 1 pcguest pcguest 707 Mar 25 00:24 bottomleft.jpg
-rw-r--r-- 1 pcguest pcguest 1603 Mar 25 00:24 bg.jpg
-rw-r--r-- 1 pcguest pcguest 3500 Mar 25 00:24 bgbottom.jpg

The destination directory is now a faithful replica of the source directory, and as you can see, the sudo command only needs to be effective for the process which is responsible for writing out the files to disk, not the reading part.

 

back

discuss (2 comments)
 by by David at 25 Mar 2006 01:43:59
What's wrong with "cp -Rp"?
by Marcos at 25 Mar 2006 14:37:24
Nothing at all. The cp command only supported these options since 2002. I guess these are the tricks we used to have to resort to in the days before these new options were available. I believe some flavours of Unix still do not support the preserve flag today, and the tar alternative is a case of 'in case of emergency, break glass' fallback alternative. This is probably what cp -Rp does underneath anyway :-)
by David at 25 Mar 2006 15:15:00
Copyrights © Transcraft Trading Limited 2006.All rights reserved. Bots Rss-rss