Generate and move thumbnails recursively

Don't iterate over the output of find. The problem you are experiencing is a typical consequence of that.

Your example is a bit tricky due to the file renaming. One not very efficient but safe way to do it is with the -exec option of find, and an additional sh per each file, like this:

find . -type f -iname "*.jpg" -exec sh -c 'echo convert "$1" -resize 800x800\> /home/user/thumbs/"${1%.jpg}_thumb.jpg"' -- {} \;

If you didn't mind using the same name (with .jpg suffix instead of _thumb.jpg), then this simple form would work, and be much more efficient:

find . -type f -iname "*.jpg" -exec echo convert "{}" -resize 800x800\> /home/user/thumbs/"{}" \;

I added echo statements there to check the output before executing the commands. Remove them if the output looks good.


You could use more advanced options like -set combined with percent escapes (namely %t to extract the filename without directory or extension) to do the resize, rename and move of each file with a single convert invocation:

find . -type f -iname \*.jpg -exec convert {} -resize 800x800\> \
-set filename:name '%t' '/home/user/thumbs/%[filename:name]_thumb.jpg' \;

In your solution the file names got split on the default $IFS which includes spaces.

Try the following:

while IFS= read -rd '' f; do

    convert ./"$f" -resize 800x800\> ./"${f%.jpg}_thumb.jpg"
    mv ./"${f%.jpg}_thumb.jpg" /home/user/thumbs/

done < <(find . -type f -iname "*.jpg" -print0)

The find prints the file names separated by null bytes (\0) and using -d '' you set the delimiter of read to the same.