wc
Count lines, words, bytes, or characters in text
wc (word count) counts lines, words, bytes, or characters in its input. With no flags it
prints all three of lines, words, and bytes; -l, -w, -c, or -m narrow it to just one.
The line count is really a newline count: wc -l counts \n characters, not visual lines.
A file whose last line has no trailing newline is undercounted by one, which surprises people
debugging an off-by-one somewhere else entirely.
-c counts bytes and -m counts characters; identical for plain ASCII, but they diverge on
multi-byte UTF-8 text, where one character can span more than one byte. Multiple file arguments
add a total line automatically; --total=always or --total=never overrides that. wc has
no flag for "non-blank lines only", so grep -c . is the usual way to get that instead.
Sample files used on this page
Every example below was run against these files. Recreate them to follow along.
report.txt 40 numbered lines, each 5 words - hence 40 lines / 200 words
line 1 of the report
line 2 of the report
line 3 of the report
…
line 40 of the report
users.csv a header row plus 6 records
name,age,department
Alice,34,Engineering
Bob,29,Sales
Carol,41,Engineering
Dave,25,Marketing
Erin,38,Sales
Frank,31,Engineering
wordlist.txt 9 lines with deliberate duplicates and mixed case
banana
apple
Cherry
apple
date
banana
apple
Elderberry
cherry
access.log 10 requests in the standard combined log format
203.0.113.5 - - [13/Aug/2026:09:12:01] "GET /index.html HTTP/1.1" 200 512
203.0.113.5 - - [13/Aug/2026:09:12:03] "GET /style.css HTTP/1.1" 200 231
198.51.100.7 - - [13/Aug/2026:09:14:22] "GET /index.html HTTP/1.1" 200 512
198.51.100.7 - - [13/Aug/2026:09:14:25] "GET /missing.html HTTP/1.1" 404 162
203.0.113.5 - - [13/Aug/2026:09:15:47] "GET /index.html HTTP/1.1" 200 512
192.0.2.44 - - [13/Aug/2026:09:16:03] "POST /login HTTP/1.1" 302 0
192.0.2.44 - - [13/Aug/2026:09:16:04] "GET /dashboard HTTP/1.1" 200 4021
198.51.100.7 - - [13/Aug/2026:09:18:51] "GET /index.html HTTP/1.1" 200 512
203.0.113.5 - - [13/Aug/2026:09:19:10] "GET /api/status HTTP/1.1" 500 89
192.0.2.44 - - [13/Aug/2026:09:20:33] "GET /dashboard HTTP/1.1" 200 4021
crlf.txt two lines with Windows CRLF endings - 14 bytes, not 12
line1␍
line2␍
filelist.bin two filenames separated by NUL bytes, for --files0-from
report.txt␀wordlist.txt␀
Counting lines, words, bytes, and characters
The four counting modes, each narrowed with a single flag.
Count lines
wc -l report.txt
-l counts newline characters - see the gotcha section below for what that means for a file with no trailing newline.
Show output
40 report.txt
Count words
wc -w report.txt
A 'word' is a maximal run of non-whitespace characters - the same definition most editors use for their own word count.
Show output
200 report.txt
Count bytes
wc -c report.txt
Raw byte count, regardless of content or encoding.
Show output
871 report.txt
Count characters
wc -m report.txt
Character count rather than byte count - identical to -c here because this file is plain ASCII, where every character is exactly one byte. They diverge on multi-byte UTF-8 text.
Show output
871 report.txt
Find the longest line
wc -L report.txt
-L reports the length of the longest line in the file, not a count at all - useful for deciding whether a file needs wrapping to fit a fixed-width display.
Show output
21 report.txt
Default output: lines, words, and bytes together
wc report.txt
With no flags, wc prints all three counts in a fixed order - lines, words, bytes - followed by the filename.
Show output
40 200 871 report.txt
Multiple files and totals
Count several files at once
wc -l users.csv wordlist.txt access.log
Each file gets its own line, plus an automatic total line summing them all.
Show output
7 users.csv
9 wordlist.txt
10 access.log
26 total
Force a total line even for a single file
wc -l --total=always report.txt
By default a lone file gets no total line since it would just repeat the count - --total=always prints one anyway, useful for consistent output in a script that sometimes gets one file and sometimes several.
Show output
40 report.txt
40 total
Suppress the total line for multiple files
wc -l --total=never users.csv wordlist.txt
The opposite override - keep the per-file counts, drop the automatic total.
Show output
7 users.csv
9 wordlist.txt
Combine short flags
wc -lw report.txt
Bundling -l and -w prints just those two counts, in that order, instead of all three defaults.
Show output
40 200 report.txt
Reading from stdin
Count lines from a pipe
cat report.txt | wc -l
No filename to print, so just the bare number comes back.
Show output
40
Count lines from redirected input
wc -l < report.txt
Redirection and piping behave identically here - both feed wc's stdin, and both print just the number with no filename.
Show output
40
Count words in a single line
echo 'the quick brown fox' | wc -w
Works the same on a single echoed line as on a whole file.
Show output
4
Measure a string's length in characters
echo -n 'hello' | wc -c
-n on echo suppresses its own trailing newline, so this counts exactly the string's own length rather than length-plus-one.
Show output
5
The no-trailing-newline gotcha
A missing final newline undercounts by one
printf 'a\nb\nc' | wc -l
wc -l counts newline characters, not lines of text. This input has three lines of content but only two \n characters - the third line has nothing after it - so wc reports 2, not 3.
Show output
2
The same content, with a trailing newline, counts correctly
printf 'a\nb\nc\n' | wc -l
Identical visible content, one more trailing newline character, and the count matches what you would expect. Most editors add this automatically; some hand-built files and command substitutions don't.
Show output
3
Using wc on real things
Count how many files matched a glob
ls *.txt | wc -l
A very common shape: pipe any line-per-item output into wc -l to get a count instead of a list.
Show output
3
Count total requests in a real access log
wc -w access.log
Not a meaningful metric on its own for a log file - shown here mainly to demonstrate that wc doesn't care what the text represents, it just counts.
Show output
90 access.log
Read a list of filenames from a NUL-separated file
wc -l --files0-from=filelist.bin
--files0-from reads the list of files to process from a NUL-separated file instead of the command line - the standard pairing with find -print0 when there could be too many files (or files with newlines in their names) for a normal argument list.
Show output
40 report.txt
9 wordlist.txt
49 total
See the effect of hidden CRLF bytes
wc -c crlf.txt
The file holds two 'lineN' lines with a trailing \r\n each, and comes to 14 bytes - 2 more than plain Unix line endings would take, from the two extra \r bytes wc -l doesn't count as separate lines but wc -c still counts as bytes.
Show output
14 crlf.txt
wc has no flag for non-blank lines - use grep instead
printf 'a\n\nb\n\nc\n' | wc -l
wc -l counts every line including blank ones - 5 here, 2 of which are blank. There's no wc flag to exclude them.
Show output
5
The actual way to count only non-blank lines
printf 'a\n\nb\n\nc\n' | grep -c .
grep -c . counts lines matching 'at least one character' - every blank line fails that match and gets excluded. See the grep page for -c and other counting patterns.
Show output
3
Total lines across every file found, via find and xargs
find . -maxdepth 1 -name '*.csv' | sort | xargs wc -l
find locates the files, xargs hands them all to a single wc invocation so the total line covers every match - see the find page for more on pairing it with other commands.
Show output
7 ./users.csv
7 ./users2.csv
14 total
Bundle lines and bytes together
wc -lc report.txt
Any combination of the short flags can be bundled - this prints just lines and bytes, skipping words and the default full trio.
Show output
40 871 report.txt
Count how many accounts exist on a system
wc -l < /etc/passwd
/etc/passwd holds a line per account, so a headcount needs no parsing of the file's colon-separated fields at all.
Show output
Your output will differ: the number of accounts is whatever your machine has; a desktop install has far more than a container
21