How to cp file and create directory if not exists?

I want to copy modified files in a svn repository to another directory, while keep their directory structure.

After reading awk and xargs manpage I find a way to get changed filenames like this:

$ svn status -q | awk '{ print $2 }' | xargs -d \\n -I '{}' cp '{}' /tmp/xen/

But the problem is that in this way directory structures are not preserved, I want to copy files like this:

./common/superp.c -> /tmp/xen/common/superp.c
./common/m2mgr.c -> /tmp/xen/common/m2mgr.c
./common/page_alloc.c -> /tmp/xen/common/page_alloc.c
./arch/x86/mm.c -> /tmp/xen/arch/x86/mm.c
./arch/x86/mm/shadow/private.h -> /tmp/xen/arch/x86/mm/shadow/private.h

I have tried to change cp command to cp '{}' /tmp/xen/'{}' but it said no such file or directory. Is there any way to make cp copy file and create directory if required? And please point out if this command chain can be simplified. :-)

Thanks for all your replies. Since the directory is a little large, I don't want to copy the whole directory using cp -R or rsync. CK's suggestion of using a tar pipe is quite useful.

svn status -q | awk '{ print $2 }' | xargs tar cf -  | (cd /tmp/xen/; tar xvf -)

Couple of quick thoughts:

  • Add in a mkdir -p $(dirname FILE)
  • Could you use a tar pipe to sort it all out?

Edit

 tar -cf archive.tar  `svn status -q | awk '{print $2}'`

Should create an archive of the modified files. Then:

  tar -xf archive.tar -C /tmp/xen

should put it where you want. If it needs to be in one step, that's possible too.


rsync makes the pretty simple, it the tool I generally use for copying entire directory structures:

rsync -av /home/source/svn/repo /home/dest/svn/

This will create the repo directory and all it contents in the /home/dest/svn directory, so you will have /home/dest/svn/repo/...

So for you example:

rsync -rv ./ /tmp/xen/

-a, would preserve time stamps and be recursive among other things, 'man rsync'.

Update after realizing I read the question wrong:

To mimic the directory structure (tar alternative):

rsync -av --include='*/' --exclude='*' source destination

And then to copy the files before say 20 minutes ago:

find . -type f -mmin -20 -print0 | xargs -0 cp --target-directory /mydestdir/

Here's that one-liner for reference:

svn status -q | awk '{print $2}' | xargs tar -c | tar -xC /tmp/xen

And in english:

  • get list of files of interest with svn status -q, which is piped into...
  • awk which extracts the column with the filepaths: awk '{print $2}'
  • xargs is used to give the list of files to tar, which in turn sends a tarball of the files to stdout: xargs tar -c
  • which is promptly re-extracted (-x) into the target directory (-C path): tar -xC /tmp/xen

Use "dirname" to extract the path "mkdir -p" to create it, something like :

xargs -d \\n -l '{}' mkdir -p \`dirname '{}'\` && cp '{}' /tmp/xen/

rsync -a does not create new directories deeper than in depth 1, so rsync is only partial solution and for example not suitable for me (I googled to find a answer how to rsync directories to some remote hierarchy when several directories are missing in the middle)

Edit: I mean, I have source dir: /home/user/projects/homework/1/1.1/ And I want to rsync it to remote:/home/user/projects/homework/1/1.1/ ...but destination does not have yet directory /home/user/projects/homework ...and I do not want to transfer other subdirectories in the source machine which are in /home/user/projects/

Edit2: Found a way, with rsync --relative option: The above example would go like this:

cd /home/projects/ ; rsync -aR homework/1/1.1 user@remote:/home/user/projects/