Count Lines, Words and Bytes Reliably with wc

Somebody asks how many lines a file has, you reach for wc, and it reports zero on a file you can clearly see has content. This guide covers a small set of wc commands for checking file sizes, counting lines and words, measuring command output, and handling a list of file names safely. The examples use GNU coreutils 9.4, installed here as package version 9.4-3ubuntu6.3.

Allow about ten minutes. You need a shell and a readable text file. The normal examples are unprivileged. Use elevated privileges only when the file permissions genuinely require them, and avoid running the whole pipeline as root just to make a count work.

1. Check the installed command

Start by confirming which implementation is in your path and which version it reports:

$ command -v wc
/usr/bin/wc
$ wc --version
wc (GNU coreutils) 9.4
$ dpkg-query -W -f='${Package} ${Version}\n' coreutils
coreutils 9.4-3ubuntu6.3

Other Unix systems may provide a different wc with fewer options. The long options and --total examples below are for this GNU version.

Checkpoint: if command -v wc points into an unexpected virtual environment, toolbox or project directory, inspect that before trusting results in a script.

2. Read the default three counts

Give wc one or more file names. With one file, its default output is newline count, word count, byte count, then the file name:

$ printf 'alpha beta\ngamma\n' > sample.txt
$ wc sample.txt
 2  3 17 sample.txt

This file has two newline characters, three words, and 17 bytes. A word is a non-empty sequence of printable characters separated by white space, a deliberately mechanical definition: punctuation attached to a word does not create a separate word.

Warning: do not read the first number as a physical line count in every situation. It counts newline characters. A final line that does not end with a newline is still content, but it does not add to wc -l.

$ printf 'without a final newline' | wc -l
      0

For text files, a final newline is usually the least surprising convention. If you are checking a generated file, inspect the file itself rather than silently treating a zero result as proof that it is empty.

3. Ask for one count at a time

Use the long options when a script or review benefits from an obvious unit:

$ wc --lines sample.txt
2 sample.txt
$ wc --words sample.txt
3 sample.txt
$ wc --bytes sample.txt
17 sample.txt

The short forms are -l, -w, and -c. You can combine them, but GNU wc prints selected counts in this fixed order: lines, words, characters, bytes, then maximum display width.

$ wc -l -w -c -m -L sample.txt
 2  3 17 17 10 sample.txt

Here -m means characters, while -c means bytes. They match for this ASCII file, but they can differ for UTF-8 text, where one visible character may occupy several bytes:

$ printf 'cafe\n' | wc -m -c
      5       5
$ printf 'café\n' | wc -m -c
      5       6

Use bytes for storage, transfer and protocol limits. Use characters when the limit is expressed in characters. -L reports the maximum display width of any input line, which is a terminal-oriented measurement, not the byte length of the longest line.

4. Count command output through standard input

With no file argument, wc reads standard input. A dash is an explicit spelling of the same input source:

$ printf 'one two\nthree\n' | wc -l -w -c
      2       3      14
$ printf 'one two\nthree\n' | wc -l -w -c -
      2       3      14

This is useful for checking a pipeline without creating an intermediate file:

$ find /var/log -maxdepth 1 -type f -print 2>/dev/null | wc -l
      6

The number depends on the machine and permissions. The command counts names emitted by find, not files that wc has opened. If the producer writes diagnostics to standard output, those diagnostics are counted too, so keep normal output and error output separate where the result matters.

5. Count several files and understand totals

When you supply more than one file, GNU wc prints one row per file and a total row by default:

$ printf 'first\n' > one.txt
$ printf 'second file\n' > two.txt
$ wc -l -w -c one.txt two.txt
 1  1  6 one.txt
 1  2 12 two.txt
 2  3 18 total

The total is not a fourth input file. It is the sum of the selected counts. GNU 9.4 lets you control it with --total=auto, always, only, or never. For example, this emits only the aggregate bytes:

$ wc --bytes --total=only one.txt two.txt
18 total

Prefer an explicit mode in automation when a later command parses the output. Otherwise, adding a second file can change the number of rows and break a brittle field extraction.

6. Process a large or awkward file list safely

Shell expansion can fail when a directory contains too many names, and newline-delimited lists cannot represent every possible Unix file name safely. GNU wc accepts a file containing NUL-terminated names:

$ printf '%s\0' one.txt two.txt > files.list0
$ wc --files0-from=files.list0 --lines --words --bytes
 1  1  6 one.txt
 1  2 12 two.txt
 2  3 18 total

The list file is data, not shell syntax. Each name must end with a NUL byte. A dash as the argument to --files0-from means read that NUL-terminated list from standard input:

$ printf '%s\0' one.txt two.txt | wc --files0-from=- --bytes --total=only
18 total

Warning: do not build a space-separated command string and evaluate it. That approach loses quoting boundaries and can turn file names into options or separate arguments. If names come from an untrusted source, validate the list and consider whether opening those paths is acceptable before running the count.

7. Diagnose failures without hiding them

A missing or unreadable file produces a diagnostic and a non-zero exit status. Capture that status immediately if a script must stop on failure:

$ wc --bytes missing.txt
wc: missing.txt: No such file or directory
$ printf 'exit status: %s\n' "$?"
exit status: 1

Check the path and permissions first:

$ test -r sample.txt && echo readable
readable
$ file sample.txt
sample.txt: ASCII text

Adding sudo can read a protected file, but it also changes which account opens it and can conceal a deployment permission problem. Use it only for a deliberate administrative check, and do not combine it with a command that writes or deletes files. wc itself does not modify its input.

Done means