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.
source to share
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
source to share
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:
-
*.png *.PNG *.jpg *.JPG *.jpeg *.JPEG *.bmp *.BMP
-
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 .
source to share