-1

I'm trying to count the number of files inside a directory while checking the sub-directories with the same script itself and sum up the results.

#!/bin/bash

var=0

var=$(ls -l $1 | grep "^-" | tr -s ' ' | cut -d ' ' -f 9 | wc -l)

 for x in `ls -lr $1 | grep "^d" | tr -s ' ' | cut -d ' ' -f 9`;
  do
        output="$($0 $x)"
        var=$((var+output)) 
 done
echo $var

However I'm not getting the right result.

What am I doing wrong?

1
  • Wouldn't want to use return or unset?
    – Xen2050
    Nov 30, 2015 at 5:15

2 Answers 2

2

To find the total number of regular files in directory $1 and its subdirectories:

find "$1" -type f -printf "1\n" | wc -l

To save that number in a variable:

var=$(find "$1" -type f -printf "1\n" | wc -l)

This will work even if file or directory names contain white space or other difficult characters.

Discussion

Let us consider this line from the original code:

 for x in `ls -lr $1 | grep "^d" | tr -s ' ' | cut -d ' ' -f 9`;

First, one should never parse ls. It is unreliable. The output of ls changes from one version to the next. Further, because of the way special characters are treated, the name displayed by ls is not necessarily the correct name of the file or directory.

Second, when using shell variables, like $1, they should be in double-quotes. Otherwise word splitting and pathname expansion is performed on them which can lead to all manor of errors.

Third, in a form like:

for x in `...`

the shell will perform word splitting and pathname expansion on the result of the command substitution. This can also lead to all manor of errors.

2
  • I know about this but I'm still trying to do it my way Nov 19, 2015 at 22:58
  • @user1326293 Hmm. I just added a section that discusses some of the issues with that way.
    – John1024
    Nov 19, 2015 at 23:03
1

… I’m not getting the right result.  What am I doing wrong?

  1. I don’t know; your script works for me (in very limited testing).
  2. John1234 discusses problems with your approach.

… I’m still trying to do it my way

Here’s an adaptation of your script that works (for me) and uses safer mechanisms:

#!/bin/bash

var=0
shopt -s nullglob

for x in "$1"/*
 do
      if [ -d "$x" ]
      then
            output="$($0 "$x")"
            var=$((var+output))
      else
            var=$((var+1))
      fi
 done
echo $var

This differs from yours in that mine will count all directory entries, other than directories, whereas yours will not count things that are not plain files (e.g., symbolic links, device nodes, named pipes, filesystem sockets, etc.)

(The shopt -s nullglob is there to handle directories that have no contents.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .