1

Let's say I'm in the Desktop directory and want to count the number of files and directories whose name is exam. It should also count the files containing the string exam. So to sum it up I need to:

  1. Count the directories with the name exam
  2. Count the files with the name and content exam

Here is what I've tried so far.

ls -l | grep -r "exam" | wc -l 

But this command counts only files with the content exam. What if I have a couple of directories: exam1, exam2, exam3, and a couple of .txt files exam1.txt, exam2.txt, exam3.txt, and want to count them?

2
  • By files containing the string exam, do you mean files whose filename contains exam (for example exam1.txt), or files whose content has exam in it? Commented Dec 28, 2018 at 12:49
  • In case of files both conditions should be met, example: filename: exam1; content: this exam was really difficult
    – KKor
    Commented Dec 28, 2018 at 13:08

4 Answers 4

3

Using find, treating directories and non-directories differently, getting the counts for directories and non-directories separately:

find . -name '*exam*' \
    \( \(   -type d -exec echo directory \; \) -o \
    \(    ! -type d -exec grep -q -wF exam {} \; -exec echo file \; \) \) |
sort | uniq -c

This would find things in or below the current directory whose names contains the string exam. If the thing is a directory, then the string directory is outputted. Otherwise, if the thing is a non-directory, and if its contents contains the word exam, then the string file is outputted. The sort and the uniq -c at the end would sort and count the number of files and directories found that matched the criteria.

Note that the test on the names may match names that contain exam as a substring, as in example for example. The grep on the files uses -w which will make it more likely that a word is matched, and not a substring.

4
  • I think you need to put (escaped) parentheses around the parenthesized expressions. That's probably because the -name test is ANDed with next expression and this has a higher precedence than the following -o. When I tested your command (without the uniq -c), it returned also regular files without exam in their name as long as there was the word exam in their content. Commented Dec 29, 2018 at 16:01
  • Actually, I just read in the man page of find that -a always has higher precedence than -o, and if the operator between two expressions is missing, -a is assumed. Commented Dec 29, 2018 at 16:21
  • @StefanHamcke Thanks, added parentheses to avoid precedences issues.
    – Kusalananda
    Commented Dec 29, 2018 at 23:39
  • Please test, as this may not find all of the files that you are looking for, so you may not get full marks for your homework. Commented Jan 19, 2019 at 22:49
1

I have done by below 2 commands

To count directories

find  path -type d -iname "exam[0-9]" | wc -l

To count number of files with condition it should have content exam in the file

find  path -type f -iname "exam[0-9]" -exec grep 'exam' {} \;|wc -l
0

Try this,

For folders:

 ls -lR * | awk -F '[ /]' ' !/^-/ && !/^d/{if ($NF ~ "exam" ) print $NF}' | wc -l

For files:

 ls -lR * | awk  '/^-/ {if ($NF ~ "exam" ) print $NF}'  | wc -l
0

The following script achieves what you want:

i=0
for file in *exam*
do
  if [ -d "$file" ] || [ -n "$(sed -n '/exam/{p;q}' -- "$file")" ]
  then
    i=$((i+1))
  fi
done
echo "Number of files: $i"

It loops over all the files whose name contains exam, and for each such file it checks whether it is a directory or it contains the string exam, and if it does, the script increases the counter by one.

Edit: I probably misunderstood your question and you want to count directories and files separately. In that case, modify the script to

i=0;j=0
for file in *exam*
do
  if [ -d "$file" ]; then
    i=$((i+1))
  elif [ -n "$(sed -n '/exam/{p;q}' -- "$file")" ]; then
    j=$((j+1))
  fi
done
echo "Number of directories: $i"
echo "Number of regular files: $j"

You must log in to answer this question.

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