1

How can I cound recursively number of files in a subdirectry in a Linux system. I know

tree
ncdu

These commands with really nice and informative output but does not cound files. I was trying to

find . -type d -print0 | xargs -0 {HERE I SHOULD DO SOMETHING}

But fail. Output like this:

00. Introduction: 6
04. Topic 1: 18
01. Topic 2: 14
02. Topic 3: 10
05. Details 4: 4
03. Conclusion: 6

There is a spaces and special characters in directory names

Ara Saahov
  • 396
  • 4
  • 6
  • 4
    Possible duplicate of [Recursively counting files in a Linux directory](https://stackoverflow.com/q/9157138/608639) – jww Oct 09 '18 at 03:02

1 Answers1

2

After researching and testing i've got

find . -maxdepth 1 -type d -print0 | sort -z | \
while IFS= read -r -d '' i ; do \
echo -n "$i: " ; (find "$i" -type f | wc -l) ; done

Explanation

-maxdepth 1 - I need only one level of recursion

-type d - only directories

-print0 | while IFS= read -r -d '' i - I have spaces in directories. The -r option to read prevents backslash interpretation (usually used as a backslash newline pair, to continue over multiple lines or to escape the delimiters). Without this option, any unescaped backslashes in the input will be discarded. You should almost always use the -r option with read.

The most common exception to this rule is when -e is used, which uses Readline to obtain the line from an interactive shell. In that case, tab completion will add backslashes to escape spaces and such, and you do not want them to be literally included in the variable. This would never be used when reading anything line-by-line, though, and -r should always be used when doing so.

By default, read modifies each line read, by removing all leading and trailing whitespace characters (spaces and tabs, if present in IFS). If that is not desired, the IFS variable may be cleared, as in the example above.

The IFS variable is used in shells (Bourne, POSIX, ksh, bash) as the input field separator (or internal field separator). Essentially, it is a string of special characters which are to be treated as delimiters between words/fields when splitting a line of input.

The default value of IFS is space, tab, newline. (A three-character string.) If IFS is unset, it acts as though it were set to this default value. (This is presumably for simplicity in shells that do not support the $'...' syntax for special characters.) If IFS is set to an empty string (which is very different from unsetting it!) then no splitting will be performed.

In the read command, if multiple variable-name arguments are specified, IFS is used to split the line of input so that each variable gets a single field of the input. (The last variable gets all the remaining fields, if there are more fields than variables.)

sort -z - sort output of find in alfabetical order

do echo -n "$i: " - print directory name and colon

find "$i" -type f - find files only inside each directory

wc -l - display number of files (lines of second find output)

Example

~/tmp$ tree
.
├── 1000
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
│   ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
│   ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   └── original_thumb.jpg
├── 10000
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10001
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10005
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10006
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10009
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 1001
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
│   ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
│   └── original_thumb.jpg
├── 10011
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10015
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10016
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   ├── 640x320_cropped_d4dcbfaafb98dafcbc594b020ce7c54b.jpg
│   └── original_thumb.jpg
├── 10017
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10018
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10019
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   ├── 640x320_cropped_d4dcbfaafb98dafcbc594b020ce7c54b.jpg
│   └── original_thumb.jpg
├── 1002
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
│   ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
│   ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   └── original_thumb.jpg
├── 10021
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10025
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 640x320_cropped_6450e078c12f532b29ba57eeb58ca8b3.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10028
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
├── 10029
│   ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
│   ├── 138x116_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_6c8e104b1fc8e31695beb9e950830d64.jpg
│   ├── 640x320_cropped_8ae863ac89a31bf9834085414215be36.jpg
│   └── original_thumb.jpg
└── 1003
    ├── 138x116_cropped_50198398faa3c0d168c176824edd4ff7.jpg
    ├── 138x116_cropped_56c7fa8bb58cca0055b0efc2c5ad303d.jpg
    ├── 138x116_cropped_c00f5791305b20d52e16e0f7a4c2e3d9.jpg
    ├── 640x320_cropped_50198398faa3c0d168c176824edd4ff7.jpg
    └── original_thumb.jpg

19 directories, 89 files

Using explained above one-liner:

~/tmp$ find . -maxdepth 1 -type d -print0 | sort -z | \
> while IFS= read -r -d '' i ; do \
> echo -n "$i: " ; (find "$i" -type f | wc -l) ; done
.: 89
./1000: 5
./10000: 5
./10001: 4
./10005: 4
./10006: 5
./10009: 5
./1001: 4
./10011: 5
./10015: 4
./10016: 5
./10017: 4
./10018: 4
./10019: 5
./1002: 5
./10021: 5
./10025: 6
./10028: 4
./10029: 5
./1003: 5
Ara Saahov
  • 396
  • 4
  • 6
  • Great work @ara-saahov, there my little hack to order by number of files find . -maxdepth 1 -type d -print0 | sort -z | \ while IFS= read -r -d '' i ; do \ l=$(find "$i" -type f | wc -l ) ; echo "$l : $i" ; done | sort -n – PaulRM Jan 21 '21 at 20:29