mrgloom
mrgloom

Reputation: 21682

How to count files per folder?

What I'm trying to do is to count json files in each folder.

My current attemp give total number of files, not per folder:

ls -d */ | xargs -I {} find {} -name "*.json" | wc -l

Upvotes: 1

Views: 1116

Answers (1)

Socowi
Socowi

Reputation: 27340

Command 1

The following command will recursively search all directories starting from the working directory. Directories containing at least one .json file will be listed with the number of json files in that directory.

find -type f -iname \*.json -exec dirname {} + | sort | uniq -c

This command assumes that all directories have single line names. It may fail in the rare case in which some directory's name contains a newline character. Some versions of dirname, sort, and uniq support null delimiters to work around this issue. Add -z to all of these commands.

Command 2

To also print the directories which do not contain any json files, you could use the following command. This command also handles newlines in directory names and allows to customize the output format (just modify the echo part).

shopt -s globstar nullglob
count() { echo "$#"; }
for d in ./ **/; do
    echo "$(count "$d"*.json) $d"
done

Example

$ tree
.
├── dir1
│   ├── dir3
│   │   ├── a.json
│   │   ├── b.json
│   │   ├── c.json
│   │   └── dir5
│   │       └── alsonotjson
│   └── dir4
├── dir2
│   ├── lorem.json
│   └── yadda.txt
├── notajsonfile
└── somejsonfile.json

5 directories, 8 files
$ find -type f -iname \*.json -exec dirname {} + | sort | uniq -c
      1 .
      3 ./dir1/dir3
      1 ./dir2
$ shopt -s globstar nullglob; count() { echo "$#"; };
$ for d in ./ **/; do echo "$(count "$d"*.json) $d"; done
1 ./
0 dir1/
3 dir1/dir3/
0 dir1/dir3/dir5/
0 dir1/dir4/
1 dir2/

Don't Recurse

To only print the working directory as well as its non-recursive subdirectories, you can ...

  • use -maxdepth 2 for the first command.
  • replace the globstar **/ with a normal glob */ for the second command.
$ find -maxdepth 2 -type f -iname \*.json -exec dirname {} + | sort | uniq -c
  1 .
  1 ./dir2
$ shopt -s nullglob; count() { echo "$#"; };
$ for d in ./ */; do echo "$(count "$d"*.json) $d"; done
1 ./
0 dir1/
1 dir2/

Upvotes: 3

Related Questions