First, why your attempt doesn't work: -printf "%h\n"
prints the directory part of the .avi
file name. That doesn't affect anything in the subsequent -exec
action — {}
doesn't mean “whatever the last printf
command printed”, it means “the path to the found file”.
If you want to use the directory part of the file name in that cp
command, you need to modify the file name before passing it to cp
. The find
command doesn't have this capability, but a shell does, so make find
invoke a shell which invokes cp
.
find . -name "*.avi" -exec sh -c 'cp -Rp "${0%/*}" /share/USBDisk1/Movies/' {} \;
Note that you'll need to pass -r
to cp
since you're copying a directory. You should probably preserve metadata such as the files' modification time, too, with -p
.
You may usefully replace cp -Rp
by rsync -a
. That way, if you've already copied a movie directory, it won't be copied again (unless its contents have changed).
Your command has a defect that may or may not affect you: if a directory contains multiple .avi
files, it will be copied multiple times. It would be better to look for directories, and copy them if they contain a .avi
file, rather than look for .avi
files. If you use rsync
instead of cp
, the files won't be copied again, it's just a bit more work for rsync
to verify the existence of the files over and over.
If all the movie directories are immediately under the toplevel directory, you don't need find
, a simple loop over a wildcard pattern suffices.
for d in ./*/; do
set -- "$d/"*.avi
if [ -e "$1" ]; then
# there is at least one .avi file in $d
cp -rp -- "$d" /share/USBDisk1/Movies/
fi
done
If the movie directories may be nested (e.g. Movies/science fiction/Ridley Scott/Blade Runner
), you don't need find
, a simple loop over a wildcard pattern suffices. You do need to be running ksh93 or bash ≥4 or zsh, and in ksh93 you need to run set -o globstar
first, and in bash you need to run shopt -s globstar
first. The wildcard pattern **/
matches the current directory and all its subdirectories recursively (bash also traverses symbolic links to subdirectories).
for d in ./**/; do
set -- "$d/"*.avi
if [ -e "$1" ]; then
cp -rp -- "$d" /share/USBDisk1/Movies/
fi
done
Best Answer
try
according to
man find