Loops are generally the wrong way to do things in shells.
Here, you could pipe a directory listing command (ls
) to a counting command (awk
):
LC_ALL=C ls -Aqn manu/ | LC_ALL=C awk ' /^-/ {if ($5 == 0) empty++; else non_empty++} END {printf "%d empty files\n%d non-empty files\n", empty, non_empty}'
Where LC_ALL=C
disables localisation, so we're sure to get a standard and consistent ls
output, and any sequence of bytes (as filenames are) form valid text.
ls -n
lists the entries of the manu
directory in long format which includes the type and size of the files, -q
guarantees one line per file even if the file names (or symlink targets) contain newline characters and -A
includes all entries, even hidden ones (not .
nor ..
which are of no use here).
Then awk
can just check the file type (first character being -
means it's a regular file) and 5th field is the size.
Add a -L
option to ls
for the type and size of file to be considered after symlink resolution. With GNU ls
, you can add -U
to disable sorting which we don't care for here.
Or you can use zsh
and its advanced globs:
empty=(manu/*(NDoN.L0)) non_empty=(manu/*(NDoN.L+0)) print "$#empty empty files\n$#non_empty non-empty files"
Where the .
glob qualifier selects regular files, L0
those of length 0 and L+0
those of length greater than 0 (and N
for nullglob
(don't complain if there's no match), D
for dotglob
(includes hidden files), oN
do N
ot o
rder the result).
for i in manu
executes exactly one iteration, settingi
equal to"manu"
.ls $i | wc -l
counts the number of lines in the listing of the file's name. It will produce0
if the file doesn't exist (becausels
then prints an error message to the error stream, and nothing on the output stream) or1
if the file exists, regardless of that file's size.