6

I have to copy a set of files from one folder to another folder and I'm using the following command:

cp -rf `head -n 100 /home/tmp/abc.txt` /home/tmp/test/files

the file contents in abc.txt is like:

./folder1/example.tar.gz
./folder2/example.tar.gz
./folder3/example.tar.gz

But while executing the above cp command I'm getting:

cp: will not overwrite just-created `/home/tmp/test/files/example.tar.gz' with `./folder3 /example.tar.gz'
cp: will not overwrite just-created `/home/tmp/test/files/example.tar.gz' with `./folder1/example.tar.gz'

I can understand that because the name of the .gz files are the same that are showing in the error. What I want to do is to have the same folder structure inside /home/tmp/test/files as listed in abc.txt, like:

/home/tmp/test/files/folder1/example.tar.gz
/home/tmp/test/files/folder2/example.tar.gz
/home/tmp/test/files/folder3/example.tar.gz

But I'm getting only one example.tar.gz inside files folder after executing the above cp command.

So what is the way to get what I mentioned above?

2 Answers 2

6

cp won't work

Your example as it stands will not work because copy doesn't copy directory structures, it will only copy the files, hence the error message you're encountering. To do a deep copy such as this you can enlist either the tar command and use the construct tar cvf - --files-from=... | (cd /home/tmp/test/files/; tar xvf -) or you can just use rsync.

rsync

If I were you I'd use rsync to do this like so:

$ rsync -avz --files-from=abc.txt /src /home/tmp/test/files/.

If you only want the 1st 100 lines from file abc.txt you can do this:

$ rsync -avz --files-from=<(head -n 100 abc.txt) /src /home/tmp/test/files/.

Example

Sample folder data:

$ tree /home/saml/tmp/folder*
/home/saml/tmp/folder1
`-- example.tar.gz
/home/saml/tmp/folder2
`-- example.tar.gz
/home/saml/tmp/folder3
`-- example.tar.gz

Now copy the files:

$ rsync -avz --files-from=<(head -n 3 /home/saml/tmp/abc.txt) \
         /home/saml/tmp/. /home/saml/tmp/test/files/.
building file list ... done
./
folder1/
folder1/example.tar.gz
folder2/
folder2/example.tar.gz
folder3/
folder3/example.tar.gz

sent 3147093 bytes  received 81 bytes  6294348.00 bytes/sec
total size is 3145728  speedup is 1.00

Confirm they were copied:

$ tree /home/saml/tmp/test/files
/home/saml/tmp/test/files
|-- folder1
|   `-- example.tar.gz
|-- folder2
|   `-- example.tar.gz
`-- folder3
    `-- example.tar.gz

tar

If you interested here's how you do it using just tar.

$ cd /home/saml/tmp
$ tar cvf - --files-from=<(head -n 3 /home/saml/tmp/abc.txt) | (cd /home/saml/tmp/test/files/; tar xvf -)
./folder1/example.tar.gz
./folder1/example.tar.gz
./folder2/example.tar.gz
./folder2/example.tar.gz
./folder3/example.tar.gz
./folder3/example.tar.gz

Confirm that it copied:

$ tree /home/saml/tmp/test/files
/home/saml/tmp/test/files
|-- folder1
|   `-- example.tar.gz
|-- folder2
|   `-- example.tar.gz
`-- folder3
    `-- example.tar.gz
5
  • but in my case i am using the head command to copy only a certain number of files, so my command is like $ rsync -avz head -n 100 /home/tmp/abc.txt /home/tmp/test/. /home/tmp/test/files This also copies only one example.tar.gz to the destination folder.what is wrong in this or how to use files-from in this command?
    – Mano
    Commented Aug 17, 2013 at 6:18
  • @user1752557 - you can use your head command as input to the --files-from= list. I'll add it to the answer.
    – slm
    Commented Aug 17, 2013 at 6:24
  • @user1752557 - see updates.
    – slm
    Commented Aug 17, 2013 at 6:40
  • Can you please tell me the version of linux which supports rsync
    – Mano
    Commented Aug 20, 2013 at 6:15
  • @user1752557 - any versions typically support it. It may not be installed but depending on the distros' package manager (apt, yum, etc.) it can be installed.
    – slm
    Commented Aug 20, 2013 at 6:26
0

The problem is most certainly not that cp doesn't copy directory structures. Of course it does: cp -r (recursive).

What cp, at least POSIX cp, doesn't do is re-create the relative paths of the source operands in the destination directory.

If you cp a/b/file1 a/b/file2 a/c/file3 dest then you get dest/file1 dest/file2 dest/file3.

If your cp is the one from GNU Coreutils, it may have the --parents option. Not sure when that was introduced. cp --parents will induce GNU cp into producing this path re-creation mechanism. From the Info documentation:

--parents
  Form the name of each destination file by appending to the target
  directory a slash and the specified name of the source file.  The
  last argument given to `cp' must be the name of an existing
  directory.  For example, the command:

      cp --parents a/b/c existing_dir

  copies the file `a/b/c' to `existing_dir/a/b/c', creating any
  missing intermediate directories.

So if you have GNU cp, the only change you need is to drop the -r since we are not recursing, and use --parents:

cp --parents -f `head -n 100 /home/tmp/abc.txt` /home/tmp/test/files

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .