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.