Count files and directories using shell script
Solution 1
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
...
Solution 2
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
Solution 3
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:
- If you want to look for files/directories in
$LOCATION
only (not recursively under their subdirectories etc), you can usefor 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). - You may want to check first that
$LOCATION
is actually a directory with[ -d $LOCATION ]
. - For arithmetic expressions, use
$(( ... ))
, for exampleFILECOUNT=$(( FILECOUNT + 1 ))
. - If you want to find all files/directories recursively, you could combine
find
with a loop.
Example:
find $LOCATION | while read item; do
# use $item here...
done
Solution 4
... 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
Solution 5
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
Alan Smith
Updated on July 11, 2022Comments
-
Alan Smith almost 2 years
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 usingif
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
-
Jite over 11 yearsNote: It counts
.
as a file too. So with only two regular files which I guess you want to count, this will print3
. -
Jite over 11 yearsThats the actual main issue in the script.
-
hovanessyan over 11 yearsHe's looking for a way to distinguish the counts of dirs and files - that's why he has 2 counters in his code. Your find gives the total count, not distinguishing between file types.
-
Alan Smith over 11 yearsThat's the answer I am looking for! Thanks. The other solutions here all counted the files and directories of the sub directories of the location as well, which I didn't want. Cheers.
-
Alan Smith over 11 yearsYes, the $LOCATION/* code worked perfectly. Why $(( ... )) instead of $[] ? Performance related?
-
dogbane over 11 yearsthis will not count dot files i.e. filenames starting with a
.
. -
Rubens over 11 years@dogbane I've added this case in the example; thanks for pointing it out. Regards!
-
Anders Johansson over 11 years@AlanSmith,
$[...]
is deprecated syntax, I can't even find it inman bash
. The modern version is$(( ... ))
(though they seem to work the same way). For your task you could just use((++FILECOUNT))
too. See stackoverflow.com/questions/2188199/…. -
gniourf_gniourf over 11 yearsThis is obviously the best possible method in this particular case! As dogbane mentioned, it handles all possible cases of files having funny symbols in their name, and also works well with directories that contain a lot of files (which is not the case for the bash solutions using globbing). One thing, though, my
find
complains about-maxdepth 1
being given after the-type f
option. (Another thing, the double quotes are not necessary here, but it never hurts to use them). -
Admin almost 6 yearsif i am using the command " find . | wc -l " it is giving 1 extra count. Like if the file count in the directory is 4 , for me this command is giving 5 in the place of 4.