0

I am working on Linux and it's new to me. I created a shell script countfiledirs. I want to know the number of files and directories in a particular directory.

My code is:

#!/bin/bash
echo "total directories:" `find . -type d | wc -l`

echo "total files:" `find . -type f | wc -l`

It's showing out as follows when I executed this command ./countfiledirs

total directories: 148
total files: 255 

I want to know how many directories and files are there if I use this command ./countfiledirs /usr/share.

dhag
  • 15,736
  • 4
  • 55
  • 65

2 Answers2

2

Files and directories can have newlines in their names, so you cannot "just" use wc -l as you are doing.

If you want a script that takes a parameter and recursively counts files and directories, you should use:

#!/bin/bash
echo -n 'total directories:'; find "$1" -type d -printf \\n | wc -l
echo -n 'total files:';  find "$1" -type f -printf \\n | wc -l

And call the script by providing the directory as commandline argument:

./your_script_name /home/e_g_your_home_dir.

Although, short, the above is of by one for the directories (unless you consider a directory to be "in" itself), you can also replace wc -l with something that can handle NUL-terminated "lines" and use -print0

#!/bin/bash
echo -n 'total directories:'; find "$1" -type d -print0 | python -c "import sys; print len(sys.stdin.read().split('\0'))-2"
echo -n 'total files:';  find "$1" -type f -print0 | python -c "import sys; print len(sys.stdin.read().split('\0'))-1"

If you don't want to do this recursively (only counting the files/directories in the directory you specify and not the ones in a directory that is in the directory you specify) you should add -maxdepth 1 after the $1 parameter.

Anthon
  • 79,293
  • Nice. I would have written your Python script as tr -cd \\0 | wc -c, but that might be less legible. – dhag May 04 '15 at 14:54
  • @dhag That would have worked as well. I know of tr, but for me the python solution is the one I can write without having to look up the syntax. The most important part is for the OP to realize that wc only works with newlines, and that those can be part of the filenames. – Anthon May 04 '15 at 19:11
  • 1
    find . -ls escapes newlines nicely – Chris Davies May 04 '15 at 19:27
  • @roiama: Excellent point. It may be worth making it explicit in your answer; at first glance I didn't think it covered filenames containing newlines. – dhag May 05 '15 at 14:05
  • @dhag That was because roalma fixed his/her broken answer after being made aware of the issue by my post (you can see that from the edit history). – Anthon May 05 '15 at 15:43
  • @Anthon: Oh OK :). That explains my false-memory impression. – dhag May 05 '15 at 15:52
  • @dhag yes thank you. I keep forgetting about files with newlines. I've seen enough reminders about them over the years (and particularly here on SE) although in nearly 30 years I've never come across one in the wild. PS I'm "he" :-) – Chris Davies May 06 '15 at 08:51
0

You need to accept the first parameter from the command line, $1. Ideally you would assign that to a variable, DIR="$1". If nothing has been provided then it seems you would want to default to the current directory .. You can do this with test -z "$DIR" && DIR='.' or, more idiomatically just use the variable and provide a default value "${DIR:-.}".

Putting that together you could have something like this:

#!/bin/bash
DIR="$1"

echo "total directories: $(find "${DIR:-.}" -type d -ls | wc -l)"
echo "total files: $(find "${DIR:-.}" -type f -ls | wc -l)"

Incidentally, the original code you posted (before I edited your question) could not have worked:

echo "total directories:" find . -type d | wc -l

You would have needed to put the find . -type d | wc -l into backticks `...`, or better still, the construct $( ... ). I've used the second approach here. For simple situations they can be equivalent, but $( ... ) is often more robust.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287