Improve loop performance

I made a small batch of script to resize (on the fly) some images:

for a in *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP} ;
do convert "$a" -resize $re "$re""_tmp/${a%.*} ["$re"].jpg" ; done

      

Performed.

Problem: if there are only (instance of) .png files inside the dir , the script runs, but some errors are displayed because there are no other file extensions ( PNG, JPG, JPG, JPEG, JPEG, BMP, BMP )

What's the best way to improve it? redirect stderr

to /dev/null

? Any ideas? I would like to check ( $?

) the exit status of the script by adding an if / then to show me if the script is working properly.

+3


source to share


2 answers


Two simple solutions from the head.

Use the parameter nullglob

to shopt

builtin
to make the non-matching globs disappear instead of the remaining literal.

$ ls *.foo
ls: *.foo: No such file or directory
$ echo one *.foo two
one *.foo two
$ shopt -s nullglob
$ echo one *.foo two
one two

      

So your script will become.



shopt -s nullglob
for a in *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP} ;
do convert "$a" -resize $re "$re""_tmp/${a%.*} ["$re"].jpg" ; done

      

Or check if the file exists before using it with conversion.

for a in *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP} ;
do [ -f "$a" ] && convert "$a" -resize $re "$re""_tmp/${a%.*} ["$re"].jpg" || :; done

      

+4


source


I would like to clarify why your script is not working as you expect, and also add another possibility just in case.

Why are you seeing errors?

This is the general way to create a loop for

:

for name [ [ in [ word ... ] ] ; ] do list ; done

      

Your code word

is *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP}

, and if you only have .png files , it expands like this:

  • Extension of the bracket :

    *.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
    
          

  • File name extension :

    file1.png file2.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
    
          

  • Example :

    $ ls
    file1.png  file2.png
    $ echo *.{png,PNG,jpg,JPG,jpeg,JPEG,bmp,BMP}
    file1.png file2.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
    
          

At this stage, these are strings that you will assign one at a time to a variable name

.
eg:$name -> *.JPG


Improving the extension with The Builtt Builtin

As a first suggestion, you can use nocaseglob

:

If set, Bash matches filenames in a case insensitive manner with filename extension.

With this option you can reduce word

to*.{png,jpg,jpeg,bmp}

  • Example :

    $ shopt -s nocaseglob
    $ echo *.{png,jpg,jpeg,bmp}
    file1.png file2.png *.jpg *.jpeg *.bmp
    
          

    Or even *.{png,jpg,jpeg,bmp}

    $ echo *.{PNG,jpg,jpeg,bmp}
    file1.png file2.png *.jpg *.jpeg *.bmp
    
          




Finally, as @Etan suggested , you can use the option nullglob

:

If set, Bash allows filename patterns that don't match any files to be expanded to line zero, rather than themselves.

  • Example :

    $ shopt -s nullglob
    $ echo *.{png,jpg,jpeg,bmp}
    file1.png file2.png
    
          


Alternatively, nullglob

in this case, you can use the option extglob

(sometimes it is enabled by default):

If set, advanced pattern matching functionality is enabled.

These are the advanced pattern matching capabilities :

?(pattern-list)
    Matches zero or one occurrence of the given patterns.
*(pattern-list)
    Matches zero or more occurrences of the given patterns.
+(pattern-list)
    Matches one or more occurrences of the given patterns.
@(pattern-list)
    Matches one of the given patterns.
!(pattern-list)
    Matches anything except one of the given patterns.

      

So, you can write word

like *.*(png|jpg|jpeg|bmp)

:

  • Example :

    $ shopt -u nullglob
    $ shopt -s extglob
    $ echo *.+(png|jpg|jpeg|bmp)
    file1.png file2.png
    
          

So it is all expanded in the File Name Extension step .

+1


source







All Articles