6

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.

4 Answers 4

11

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

find /source -regextype posix-extended -regex '.*(gif|jpg)' \
    -exec cp --parents {} /dest \; -print
0
2

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
0

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.

0

Same answer but for Mac, since --parents is not available for cp on a Mac.

 find /source/dir -type f \( -iname "*.jpg" -o -iname "*.png" -o -iname "*.jpeg"   \) -exec rsync -R {} ../destination/dir \;

You must log in to answer this question.

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