When line counting gives unexpected results, we should check if each text processing utility understands what a line is the same way. This usually boils down to two questions:
1) File conversion issues: What charactes(s) are used as the EOL (end-of-line aka newline or line break)? It could be
\r\n depending on the OS.
2) Is the very last line also terminated with the EOL? If not, how the text processing utilities handle it?
In this case the second question was leading to an explanation.
What does the
wc -l count?
Directly from the man page:
-l, --lines print the newline counts
Obviously, the last line is not counted, if it happens to be not terminated with a newline, i.e. the result is then one less than the real number of lines.
grep terminates each output line with a newline. I did not find it in the documentation, only tested it.
We can now make a test to explain the behaviour described in the question:
- Let's create a test file with 3 lines but without a trailing newline
echo -ne "first\nsecond\nthird" > 3lines.txt
- Let's check the last character:
tail -1 3lines.txt | od -c
Ok, no '\n'.
wc -l < 3lines.txt
Output is: 2 (last line not counted, because last newline is missing)
- Pass all lines through grep
grep . < 3lines.txt | wc -l
Output is 3 (all lines counted, because no newline is missing)
- Filter out just one line (it can be any line)
grep -v first < 3lines.txt | wc -l
Output is 2 (again all lines counted).