Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I am trying to resize all files that are found using a FIND command (they are all files within a directory and its subdirectories). I tried many options but stumble across different errors each time. This is my last attempt:

find /my/folder/ -name '*jpg' -exec 'mogrify -resize 900">"{}' \;

I tried many others but to no avail. What goes wrong?

share|improve this question
    
what exactly is the command you're trying to run? mogrify -resize 900">" foo.jpg ? –  DerfK Jan 28 '11 at 21:55

4 Answers 4

up vote 11 down vote accepted

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)

share|improve this answer
    
Ha this time you beat me @lynxman! I seriously have to write a blog post '-exec considered harmful`. Oh and I will give you an upvote in a couple hours after my daily limit expires. –  Phil Hollenback Jan 28 '11 at 21:55
    
Thanks! But I get: xargs: invalid option -- 'J' Also, mogrify -resize 900">"foo.jpg will resize it only IF wider than 900 pixels (therefore the ">" between quotes. –  user60129 Jan 28 '11 at 21:58
1  
On my xargs here you'd want xargs -0 -I% mogrify -resize 900">" % –  DerfK Jan 28 '11 at 22:00
    
Totally awesome; works like a charm. Thanks all! –  user60129 Jan 28 '11 at 22:07
1  
mikelikespie see my answer for an alternative way to do the same thing a bit more awesomely via gun parallel. –  Phil Hollenback Jan 29 '11 at 6:21

Its old here but no one said anything about a simple:

ls | xargs mogrify -resize 900

that will deal with all files in current directory -good for a thunar custom action too, add -quality xx as well.

Or for custom action on only selected files:

mogrify -resize 900 %F

share|improve this answer
1  
Don't use ls. It's not designed for that. Use a Glob. –  Tom O'Connor Jul 11 '12 at 19:59
    
sorry? so far I've used it and it works pretty well! –  dav Jul 11 '12 at 20:01
    
ok I follow, but supposing the directory has .jpg and .jpeg extensions, will the .jpeg files be missed out if the glob is *.jpg ? –  dav Jul 11 '12 at 20:04
    
extended globbing and use *.(jpg|jpeg) or similar - linuxjournal.com/content/bash-extended-globbing –  Tom O'Connor Jul 11 '12 at 20:31
    
It's not unusual for JPEG files to have spaces in their names. This command won't work in that case. –  Dennis Williamson Jul 12 '12 at 2:24

@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.

share|improve this answer
    
Amazing work Phil! \o/ –  lynxman Jan 28 '11 at 22:38
1  
Thanks for the education here! I tried to make it would and couldn't, though. The -0 flag is a tipo I guess in the parallel command, but even without that it just prints the commands with no results. BTW: with mogrify -resize">"200 you resize an image to 200 ONLY if it is larger than 200 (so only decreasing, no increasing). VERY useful. –  user60129 Jan 28 '11 at 23:12
    
huh let me retry and fix. -0 is definitely a valid option for parallel. Could you maybe have an old version? Not sure. –  Phil Hollenback Jan 29 '11 at 0:24
    
Small optimizations: -0/-print0 is only needed if the filename contains \n (space or ' or " are not a problem). -j +0 has been default since 20110122. {} is added if {} is not in the command. Only special chars needs to be quoted. So this should be equivalent: find /my/folder -name '*jpg' | parallel --progress mogrify -resize 800"\>" See GNU Parallel if you are at FOSDEM fosdem.org/2011/schedule/event/parallel –  Ole Tange Jan 29 '11 at 15:16
1  
Thanks Ole for the tips. I'm still learning parallel obviously. –  Phil Hollenback Jan 29 '11 at 18:10

Edit: Sorry, I just realized that's not redirection in your command. It's a special instruction to mogrify.

I would omit the single quotes and try this:

find /my/folder/ -name '*jpg' -exec mogrify -resize 900">" {} \;

Using the command as you posted it, you're probably getting error messages like:

find: `mogrify -resize 900">"filename': No such file or directory.

Original Answer:

To make redirection work within -exec you need to use sh -c:

find /my/folder/ -name '*jpg' -exec sh -c 'mogrify -resize 900 > "$@" ' _ {} \;

It's only been in the last few days that I've started seeing people question the use of -exec. I haven't seen anyone say specifically what's wrong with it. I have a lot of experience with using it and it's never failed me. However, there are times that xargs is definitely advantageous because of the control it provides and its ability to pass multiple arguments at the same time. However, when you use -I, it only passes one argument at a time. The command I've shown here does have the disadvantage of invoking the shell for each found file.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.