There are several potential problems with the accepted answer:
- it does not descend into subdirectories (without relying on non-standard shell features like
globstar
)
- in general, as pointed out by Dennis Williamson below, you should avoid parsing the output of
ls
- namely, if the user or group (columns 3 and 4) have spaces in them, column 5 will not be the file size
- if you have a million such files, this will spawn two million subshells, and it'll be sloooow
As proposed by ghostdog74, you can use the GNU-specific -printf
option to find
to achieve a more robust solution, avoiding all the excessive pipes, subshells, Perl, and weird du
options:
# the '%s' format string means "the file's size"
find . -name "*.txt" -printf "%s\n" \
| awk '{sum += $1} END{print sum " bytes"}'
Yes, yes, solutions using paste
or bc
are also possible, but not any more straightforward.
On macOS, you would need to use Homebrew or MacPorts to install findutils
, and call gfind
instead. (I see the "linux" tag on this question, but it's also tagged "unix".)
Without GNU find
, you can still fall back to using du
:
find . -name "*.txt" -exec du -k {} + \
| awk '{kbytes+=$1} END{print kbytes " Kbytes"}'
…but you have to be mindful of the fact that du
's default output is in 512-byte blocks for historical reasons (see the "RATIONALE" section of the man page), and some versions of du
(notably, macOS's) will not even have an option to print sizes in bytes.
Many other fine solutions here (see Barn's answer in particular), but most suffer the drawback of being unnecessarily complex or depending too heavily on GNU-only features—and maybe in your environment, that's OK!