Request for input on bash script loop

157 views Asked by At

I am trying to run jpegoptim against pictures and at some point in the loop...after let's say 200 iterations, i get "stdin", which requires input to go further.

Is there a way to force the input?

#!/bin/bash
for i in `find . -name "*.jpg" -type f`; do
  jpegoptim "$i" >> jpg.log; done
done
2

There are 2 answers

1
Paul Hodges On BEST ANSWER

First, don't process dynamically generated file lists in a for loop.

Second, your code is broken - you have 2 done's.

Third, my apologies, not familiar with the tool, but I'm inclined to think your issue is in a broader piece of the code than presented.

Fourth, (getting minor and nitpicky :) prefer $(...) over backticks. There is very rarely a reason not to do so in bash.

Still, almost none of that is relevant to your question, aside from maybe the third thing... See if this helps -

find . -name "*.jpg" -type f |
  while read -r file; do jpegoptim "$file"; done >> jpg.log 2>&1

Or possibly better,

find . -name "*.jpg" -type f | xargs jpegoptim  >> jpg.log 2>&1

Update

Benjamin W. points out that these break when filenames have embedded newlines, which is entirely true. I consider filenames with embedded newlines a heinous heresy of the highest order, nut sometimes you don't have control of that, so per his entirely valid suggestion:

find . -name "*.jpg" -type f |
  while read -r -d '' file; do jpegoptim "$file"; done >> jpg.log 2>&1

or

find . -name "*.jpg" -type f -print0 | xargs -0 jpegoptim  >> jpg.log 2>&1

or best, for simplicity and (therefore) safety

find . -name "*.jpg" -type f -exec jpegoptim {} \; >> jpg.log 2>&1

(Please check my syntax on those...)

Though there are still efficiency considerations if you are processing a large number of files. One should also consider the possibility that the target program may or may not be able to multiprocess command-line arguments. Consider the difference between these:

$: find /tmp -type f -exec echo {} \;
/tmp/.mintty-version
/tmp/AdobeARM.log
/tmp/foo
. . . 

$: find /tmp -type f | xargs echo
/tmp/.mintty-version /tmp/AdobeARM.log /tmp/foo ...
0
ssemilla On

You can use a counter then ask for user input using read when the counter reaches 200

#!/bin/bash

count=0
for i in `find . -name "*.jpg" -type f`; do
    jpegoptim "$i" >> jpg.log
    [[ $((count++)) == 200 ]] && read -rp "Continue? [y/n] " resume
    [[ "$resume" == 'n' ]] && break
done