find -exec in bash script with variable expansion

You need to pass {} as an argument to the shell then loop over each arg.

find "$sourcedir" -type f -name "*.type" -exec sh -c 'for f; do cp "$f" "$0"; done' "$targetdir" {} +

Note: The way this works is that the first arg to a shell is the name of the shell, we can exploit this by passing the name as the $targetdir and then use the special parameter $0 inside the shell script to access that targetdir.


You want to copy files of a specific type, to a specific directory? This is best done with xargs, and you don't even need that sh. This is a more appropriate way to do it, should also run more efficiently.

find "$sourcedir" -type f -name "*.type" | xargs cp -t targetdir

If you need to handle special file names, then use NULL as your seperator

find "$sourcedir" -type f -name "*.type" -print0 | xargs -0 cp -t "$targetdir"

If you don't believe in the church of xargs:

find "$sourcedir" -type f -name "*.mp3" -exec cp -t "$targetdir" {} +

Explanation:

cp -t a b c d 

copies b, c and d to the target dir a.

-exec cmd {} +

invokes the command on a big bunch of files at once, not one after the other (which is standard, if you use ";" instead of +) . This is why have to pull the targetdir to the front and mark it explicitly as target.

This works for gnu-find and might not for other implementations of find. Of course it relies on the -t -flag too.

TechZilla is of course in so far right, as sh isn't needed to invoke cp.

If you don't use xargs, which is most of the time needless in combination with find, you're saved from learning the -print0 and -0 flag.