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 want to copy all the .html files in myDir and its subdirectories to ~/otherDir. Here's what I tried (it doesn't work):

$ find myDir -name *.html -print | xargs -0 cp ~/otherDir
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
       cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory
share|improve this question

5 Answers 5

up vote 3 down vote accepted

find myDir -name '*.html' -print0 | xargs -0 -J % cp % ~/otherdir

share|improve this answer
    
-J is not in gnu xargs (4.4.2) –  simpatico Jun 2 '11 at 21:29
    
@simpatico: It's a BSD extension, allowing passing multiple elements even when there are subsequent arguments. There's no GNU equivalent AFAIK. –  Gilles Jun 3 '11 at 17:38

Does OSX support -execdir for find?

 find ./myDir -name "*.html" -execdir cp {} /abspath/to/otherDir ";"

Gnu/find suggests using -execdir instead of -exec for most cases.

share|improve this answer
    
It does. So do all (recent enough) BSDs. -execdir is better in case a directory is moved while find is operating, but it's unfortunately not portable. –  Gilles Jun 3 '11 at 17:35

So you want to copy all the .html files in some source directory and its subdirectories, all to a single directory (i.e. collapsing the hierarchy)?

POSIX Standard:

find myDir -name '*.html' -type f -exec sh -c 'cp "$@" "$0"' ~/otherDir {} +

Note that ~/otherDir becomes parameter 0 to the intermediate shell, which allows for the source files to be precisely "$@". Leaving the target directory outside the shell has the additional advantage that you won't run into quoting issues if that's a variable in the parent shell script (-exec sh -c 'cp "$@" "$0"' "$target").

For older systems that don't have find … -exec … +:

find myDir -name '*.html' -type f -exec cp {} ~/otherDir \;

I your shell is bash ≥4 or zsh:

shopt -s globstar  # only for bash, put it in your `.bashrc`
cp myDir/**/*.html ~/otherDir/
share|improve this answer
    
setopt globstar doesn't work on bash 4.2 both on mac and linux. –  simpatico Jun 3 '11 at 16:42
    
@simpatico: Sorry, that's shopt -s (setopt is the corresponding command in zsh). –  Gilles Jun 3 '11 at 16:58
    
Isn't -type f evaluated after -name "*.html"? While a.html is a valid directory name, I wouldn't expect one. Maybe -type f would make more sense before checking the file name, but I guess there is rarely a difference in the execution speed. –  user unknown Jun 3 '11 at 17:23

First of all, the shell is globbing the '*' for you. Either escape it with \ or use quotes around *.html

Like so:

find myDir -name "*.html" or find myDir -name \*.html

Skip the use of xargs with find's -exec switch:

find myDir -name "*.html" -exec cp {} ~/otherDir \;

This works because {} takes the place of the file that find found, and is executed once for each match.

Also note that this will flatten the copy of the source directory. Example:

myDir/a.html
myDir/b/c.html

will yield

otherdir/a.html
otherdir/c.html
share|improve this answer
    
on the mac I don't have -t but $ find MR -name "*.html" -exec cp ~/debug {} \; prints: "cp: /Users/simpatico/debug is a directory (not copied)." for each html file –  simpatico May 10 '11 at 20:03
    
Oh, you didn't mention that in your question. It would probably be helpful to others if you could tag your question with "osx". You can still do this with -exec - I'll edit my answer. –  Miles Strombach May 10 '11 at 20:20
    
Worse, it will also copy both mydir/a/a.html and mydir/b/a.html to otherdir/a.html and it's not entirely obviously predictable which one winds up copied over last, which is probably not something you want... –  Shadur May 11 '11 at 6:42
1  
@simpatico, you got the order wrong. It's -exec cp {} ~/debug/ \; not -exec cp ~/debug {} \; for what should be fairly obvious reasons once you think about it... –  Shadur May 11 '11 at 6:43

Try

find myDir -name '*.html' -exec cp -t ~/otherdir {} +

One problem with this approach is that it doesn't create any subdirectories so all files get put in ~/otherDir and files that are named the same but in different parts of the myDir tree don't get copied.

If this would cause you a problem then you can use the following to create the same directory tree within the ~/otherDir tree

find myDir -name '*.html' | cpio -pdm ~/otherdir

I don't have a mac

find myDir -name '*.html' -print | xargs -I {} cp  {} ~/otherDir

or if you can

find myDir -name '*.html' -print0 | xargs -0 -I {} cp  {} ~/otherDir

as this will be safe for files with spaces in the name.

share|improve this answer
    
@lain - did you notice my mac limited cp w/o -t? I actually intend not to copy the structure, so cmd would be ideal if it worked, but writing the cmd w/o -t doesn't do the trick (I still get the usage printed). –  simpatico May 10 '11 at 19:59

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.