Bash: execute command on results of FIND

Solution 1:

I don't like exec on find very much, it's a bit ancient and unpredictable specially when you feed it all the quotes :)

Try using xargs, it should behave a bit more civilized

find /my/folder/ -name '*jpg' -print0 | xargs -0 -J% "mogrify -resize 900 > %"

Things that are different here

-print0 on find appends a NULL character after each filename as separator

in xargs

-0 tells that the input is separated by NULL char -J% says that % should be replaced by the content in the input (filename in this case)

Solution 2:

@lynxman nailed the traditional advice of find/xargs. However another alternative is to use find with gnu parallel. Parallel offers some neat enhancements to xargs like more sophisticated argument handling and the ability to run many jobs in parallel (I realize that some newer versions of xargs do support parallel jobs too).

So, lets see if we can rewrite this in parallel. How about:

find /my/folder -name '*jpg' -print0 | parallel --progress -0 -j +0 "mogrify -resize 900\> {}"

that will find all jpeg files and run them through parallel. parallel will run as many jobs in parallel as you have cpu cores (-j +0).

If you are processing a lot of files, you could gain some significant time savings by intelligently batching the jobs like this. The --progress option displays some details as the job is running.

The -print0 from the find command uses nulls to separate the output, in case you have spaces or weird characters in your filenames. The -0 option to parallel expects input separated with nulls. If you are sure your input filenames don't contain spaces, you can omit -print0 / -0. Note that most versions of xargs also takes the -0 option so you can use this trick with xargs as well as with parallel.

EDIT: From comments I didn't get the commands quite right. Adjusted mogrify now that I actually tried to use it. Don't need to save to new files because mogrify writes to the existing file by default.