Reputation: 9474
I am trying to find out no.of files of particular type. If file exists then this script works fine, else for loop executed once(which is not expected to run).
echo "Checking for text files..."
j=0
for i in *.txt;
do
echo $i;
j=`expr $j + 1`;
done
if [ $j -ge 0 ];then
echo "No.of Text files:"$j
else
echo "No Text files."
fi
There may be some other way to same thing like ls *.txt |xargs ...
. But as a newbie I would like to know the problem in the posted script. I request you to share your knowledge in this regard.
Upvotes: 2
Views: 107
Reputation: 200273
When there's no matching file for the pattern *.txt
, it's interpreted as a literal string "*.txt"
. That's why your loop runs at least once.
There are several ways to deal with this issue. You could add a check for the presence of matching files like this:
if ls *.txt >/dev/null 2>&1; then
for i in *.txt; do
...
done
fi
Depending on what you want to do inside the loop, you could also use find
:
find . -maxdepth 1 -name "*.txt" | while read i; do
...
done
Some things, however, won't work with this construct (like incrementing $j
), because the while
loop runs in a subshell, so all changes to $j
are lost when the subshell exits (i.e. the loop terminates).
As a side note: I'd change the incrementation of $j
from j=`expr $j + 1`
to ((j++))
.
Upvotes: 1
Reputation: 46823
There are no problems in your script, really, except that it could be written in a better style, using modern builtins and except that it fails if there are no text files, see below.
echo "Checking for text files..."
j=0
for i in *.txt; do
echo "$i"
((++j))
done
if ((j!=0)); then
echo "No. of Text files: $j"
else
echo "No Text files."
fi
When using globbing, it's always a good practice to use either nullglob
of failglob
.
failglob
will raise an error if the glob can't be expanded,nullglob
will just expand to nothing if there are no suitable expansions.without these, *.txt
will expand to *.txt
(verbatim) if there are no suitable expansions, which is exactly what you want to avoid!
In your case, just put
shopt -s nullglob
at the top of your script and you're done!
Now a possible way to count the number of *.txt
files could be:
shopt -s nullglob
a=(*.txt)
echo "There are ${#a[@]} text files"
What is this fuss about nullglob
and failglob
?
Let's go in a scratch directory:
$ mkdir scratch; cd scratch
$ # this dir is empty
$ echo *.txt
*.txt
$
because the glob has no suitable expansion there. Now:
$ shopt -s nullglob
$ echo *.txt
$
because of the nullglob
. Now we'll unset nullglob
and set failglob
:
$ shopt -u nullglob
$ shopt -s failglob
$ echo *.txt
bash: no match: *.txt
$
Get it?
The bottom line is: Each time you're using globbing in bash, use failglob
or nullglob
to make your scripts more robust.
As a tongue in the cheek bottom line: Each time you use globbing without failglob
or nullglob
, God kills a kitten.
If you want more information about shopt
and shell optional behaviour, please referer to The Shopt Builtin section in the manual.
Upvotes: 5