5

I was using this little script to find malformed images:

find -name '*.jpg' -exec identify -format "%f\n" {} \; 2>errors.txt

It worked well enough, but now I need to modify it slightly. Instead of dumping the stderr to errors.txt, I want to dump the filename (%f) of the image that triggered the error. That is, I want a list of the malformed image files in errors.txt instead of a list error messages.

I tried adding || echo "%f" >> errors.txt to the -exec portion, but that didn't work. What would be the best way to do this?

0

3 Answers 3

7

This finds malformed images and stores their names in names.txt:

find -name '*.jpg' -exec bash -c 'identify "$1" &>/dev/null || echo "$1">>names.txt' none {} \;

How it works

  • find -name '*.jpg'

    This starts up find as usual.

  • -exec bash -c 'identify "$1" &>/dev/null || echo "$1" >>names.txt' none {} \;

    This runs identify on each file and, if identify returns a non-zero error code, it echoes the file name to names.txt.

    bash -c '...' none {} causes a bash shell to run the command in the quotes with the file name in {} assigned to positional argument $1.

    For the curious, the string none is assigned to $0. $0 is not used unless bash generates an error in which case it will appear in the error message as the program name.

Discussion

I tried adding || echo "%f" >> errors.txt to the -exec portion, but that didn't work. What would be the best way to do this?

The subtlety is that the || has to operate on the identify command. To do that, we need to put identify in a shell such as by using bash -c as shown above.

2
  • Works great, and thanks for the explanation -- the 'bash' addition makes perfect sense. One minor thing: I had to change >names.txt to >>names.txt in order to get a list.
    – Phll
    Apr 11, 2015 at 23:15
  • @Phll Glad it worked for you. Sorry about the > thing: the answer is now corrected.
    – John1024
    Apr 12, 2015 at 1:08
2
find . -name '*.jpg' -exec sh -c '
  for file do
    if identify "$file"; then
      printf "%s\n" "$file" >&3
    else
      printf "%s\n" "$file" >&4
    fi
  done' sh {} + 3> good 4> bad > /dev/null 2>&1
1

So you want like...

find . -name '*.jpg'  \
       ! -exec identify -silent {} \; \
       -print 2>/dev/null >errors.txt

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.