Reputation: 1169
I'm learning bash scripting and have written a script to count the files and directories in the directory that is supplied as argument. I have it working one way which seems odd to me and am wondering if there is a simpler way of doing it.
I have commented out the code that will work, but left it in as a comparison. I am trying to get the for
-loop working, instead using if
statements inside it to detect if an item in the given location is a file or a directory.
Edit: I just found out that the commented code counts all files and directories in the subdirectories of the given location as well! Is there any way to prevent this and just count the files and directories of the given location?
#!/bin/bash
LOCATION=$1
FILECOUNT=0
DIRCOUNT=0
if [ "$#" -lt "1" ]
then
echo "Usage: ./test2.sh <directory>"
exit 0
fi
#DIRS=$(find $LOCATION -type d)
#FILES=$(find $LOCATION -type f)
#for d in $DIRS
#do
# DIRCOUNT=$[$DIRCOUNT+1]
#done
#for f in $FILES
#do
# FILECOUNT=$[$FILECOUNT+1]
#done
for item in $LOCATION
do
if [ -f "$item" ]
then
FILECOUNT=$[$FILECOUNT+1]
elif [ -d "$item" ]
then
DIRCOUNT=$[$DIRCOUNT+1]
fi
done
echo "File count: " $FILECOUNT
echo "Directory count: " $DIRCOUNT
For some reason the output of the for
-loop, no matter where I point the location to, always returns:
File count: 0 , Directory count: 1
Upvotes: 20
Views: 82750
Reputation: 14768
You're not iterating over the list of files inside the given directory; add /*
after $LOCATION
. Your script should look like:
...
for item in $LOCATION/*
do
...
As pointed by dogbane, just adding /*
will count only files that does not begin with .
; for doing so, you shall do the following:
...
for item in $LOCATION/* $LOCATION/.*
do
...
Upvotes: 5
Reputation: 274612
Use find
as shown below. This solution will count filenames with spaces, newlines and dotfiles correctly.
FILECOUNT="$(find . -type f -maxdepth 1 -printf x | wc -c)"
DIRCOUNT="$(find . -type d -maxdepth 1 -printf x | wc -c)"
Note that the DIRCOUNT
includes the current directory (.
). If you do not want this, subtract 1.
((DIRCOUNT--)) # to exclude the current directory
Upvotes: 20
Reputation: 4006
To just solve the problem you can use:
FILECOUNT=$(find $LOCATION -type f | wc -l)
DIRCOUNT=$(find $LOCATION -type d | wc -l)
find
will look for all files (-type f
) or directories (-type d
) recursively under $LOCATION
; wc -l
will count the number of lines written to stdout in each case.
However if you want to learn, the bash script may be a better way. Some comments:
$LOCATION
only (not recursively under their subdirectories etc), you can use for item in $LOCATION/*
, where the *
will expand to the list of files/directories in the $LOCATION
directory. The missing *
is why your original script returns 0/1 (becasue the $LOCATION
directory itself is the only item counted).$LOCATION
is actually a directory with [ -d $LOCATION ]
.$(( ... ))
, for example FILECOUNT=$(( FILECOUNT + 1 ))
.find
with a loop.Example:
find $LOCATION | while read item; do
# use $item here...
done
Upvotes: 15
Reputation: 35018
Use
find $LOCATION -maxdepth 1 -type f | wc -l
For the count of files, and
find $LOCATION -maxdepth 1 -type d | wc -l
For counting directories
Upvotes: 2
Reputation: 47267
... am wondering if there is a simpler way of doing it.
If you say so ;)
Alternatively, reduce your script to
find /path/to/directory | wc -l
For current directory, do:
find . | wc -l
Upvotes: 4