user1992348
user1992348

Reputation: 113

Shell Script to Display Number of Files and Directories in a Directory

I'm trying to write a script that will tell you how many files and how many directories are in a given directory.

Here's the script I've written, but the output is always "Number of files is ." and "Number of directories is ."

Here's my code:

#!/bin/sh
if [ -d "$@" ]
then
find "$@" -type f | ls -l "$@" | wc -l | echo "Number of files is $@"
find "$@" -type d | ls -l "$@" | wc -l | echo "Number of directories is $@"
fi

Upvotes: 2

Views: 27938

Answers (2)

Kevin
Kevin

Reputation: 1569

You seem to be confused on piping here.

You want the output of find ... | wc -l to be expanded in the echo command.

So, your script, given what you want to accomplish should look something like this:

#!/bin/sh

if [ -d "$@" ]; then
    echo "Number of files is $(find "$@" -type f | wc -l)"
    echo "Number of directories is $(find "$@" -type d | wc -l)"
else
    echo "[ERROR]  Please provide a directory."
    exit 1
fi

Upvotes: 2

Adrian Frühwirth
Adrian Frühwirth

Reputation: 45696

You seem to be having difficulties to understand how pipes work. You cannot "natively" use the "result" (stdout) of a pipe (the left-hand side) as a variable on the right-hand side of a pipe, you either need to consume and read it into a variable, e.g.

printf "line1\nline2\n" | while read line; do_stuff_with "${line}"; done

or you need to use command substitution (and optionally assign it to a variable), e.g.

files=$(find "$1" -maxdepth 1 -type f -printf . | wc -c)

A few further notes:

  • $@ expands to all positional parameters, in case of multiple arguments your [ -d "$@" ] will fail.
  • The ls is completely superfluous
  • find works recursively, but I guess you only want the first directory level to be checked so this needs the maxdepth parameter
  • This will break on weird paths with newlines which can be worked around by telling find to print a character for each found directory/file and then count bytes instead of lines

In case you really don't want this to be recursive it might be easier to just use globbing to obtain the desired result:

$ cat t.sh
#!/bin/bash

for file in "${1-.}"/*; do
        [ -d "${file}" ] && ((directories++))
        [ -f "${file}" ] && ((files++))
done

echo "Number of files: ${files-0}"
echo "Number of directories: ${directories-0}"

.

$ ./t.sh
Number of files: 6
Number of directories: 1

$ ./t.sh /tmp
Number of files: 9
Number of directories: 3

You might want to check man test to tweak with regards to links to obtain your desired result.

Upvotes: 5

Related Questions