Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm working on a website migration. I have a scrape of the site, with all the files and directory structure as you would see them in the URL. I want to pull all images, maintaining the directory structure, and copy them into a new place.

For instance, if I have

/content1/index.php
/content1/page2.php
/content1/images/image1.jpg
/content1/images/image2.jpg
/content1/background/spacer.gif
/content1/background/background.gif
/content2/index.php
/content2/images/image3.jpg
/content2/background/spacer.gif
/content2/background/background.gif

Then I want

/content1/images/image1.jpg
/content1/images/image2.jpg
/content1/background/spacer.gif
/content1/background/background.gif
/content2/images/image3.jpg
/content2/background/spacer.gif
/content2/background/background.gif

I can use the find command to get a list of only image files, but I don't know how to manipulate each file while preserving the directory path to it.

I could make a copy of the entire directory, and then recursively delete any non-image file, but now that I have set this problem before myself, I figure its worthwhile to know how to do it, in case I really do need to do it this way later.

share|improve this question
add comment

3 Answers

up vote 7 down vote accepted

Try this command (find and cp with --parent option):

find /source -regextype posix-extended -regex '.*(gif|jpg)' \
    -exec cp --parents {} /dest \; -print
share|improve this answer
add comment

Use pax (or one of its predecessors cpio or tar) in copy-through mode. Tell it to copy only the desired files (.jpg or .gif). The syntax is a little roundabout: the -s option specifies how to rename files; renaming a file to an empty name means it won't be copied, and since the first match applies, to exclude most files, the trick is to rename files that you want to include to themselves, and exclude the rest. Directories won't be copied this way, but if pax copies foo/bar/qux.jpg then it will create foo and foo/bar on the destination if necessary, and pax recurses even inside excluded directories.

pax -rw -pp -s '!\.gif$!&!' -s '!\.jpg$!&!' -s '!.*!!' /content* /destination

You can also use rsync to perform the copy, but it's clumsier. Since rsync doesn't copy excluded directories, you either need to include all directories and remove the empty ones afterwards, or to generate the list of directories to copy. See this answer for explanations.

rsync -a --include='*.gif' --include='*.jpg' --include='*/' \
      --exclude='*' /content* /destination
share|improve this answer
add comment

Assuming we want to copy all *.conf files from /etc/ to /tmp/ I whould do:

tar c $(find /etc/ -name '*.conf') | tar xv -C /tmp

How it works:

  1. create list of files to be copied by proper $(find ...)
  2. tar c create new tar archive and pass it to stdout
  3. | pipe that archive to another tar process to unpack
  4. tar xv verbose extract archive read from stdin but with directory changed to /tmp (destination).

This method will not work correctly with files with spaces in it. To fix than you can generate list of files and pass it first tar command via -T option.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.