群里有人问“Linux怎么统计文件行数”,十几个人抢着回答。有人说wc -l,有人说cat -n | tail -n 1,还有人说用awk。我在旁边看了半天,发现这个问题看着基础,但要针对不同场景把统计方法说清楚,其实能讲出来一堆门道。后来我把日常工作中真正用到的统计姿势整理了一遍,发现里面的坑比想象中多:wc -l不是严格意义上的数行数、grep -c的退出码会在脚本里坑人、find配合xargs批量统计时遇到空输入会莫名其妙卡住。这篇就把这些全部展开,给有同样需求的人一个完整参考。
1. wc -l直接上手,但先搞清楚它到底在数什么
1.1 最基础用法和“少一行”的陷阱
命令行统计文件行数,绝大多数人第一个想到的就是wc -l。wc是word count的缩写,-l表示lines,用法很简单:
bash复制wc -l /etc/passwd
输出结果是行数加文件名,比如45 /etc/passwd。如果不想看到文件名,可以配合管道:
bash复制cat /etc/passwd | wc -l
但这个命令在追求简洁的人眼里会有点“多余”,因为wc本身就能直接读文件,非要开一个cat进程再喂给wc,属于典型的UUOC(useless use of cat)。我自己写脚本时一般直接wc -l file,只有在需要把多个文件内容合并统计时才会让cat上场。
真正要小心的是“少一行”的问题。wc -l统计行数的底层逻辑是统计换行符\n的个数,而不是统计“有多少行文本”。这两个概念大多数情况下一致,但有一个经典例外:文件最后一行末尾没有换行符时,wc -l会把最后一行漏掉。
举个例子:
bash复制printf 'a\nb\nc' > test.txt
wc -l test.txt
输出是2,但用编辑器打开会看到三行文本。printf 'a\nb\nc'只写了两个换行符,最后一行c后面没有任何终止符,所以wc -l只数到2。再看:
bash复制printf 'a\nb\nc\n' > test.txt
wc -l test.txt
这次输出是3,因为最后一个\n也补上了。
很多编辑器默认保存文件时会在末尾自动加换行,但脚本生成的文件、从Windows上传的文件、某些工具导出的文件不一定有这个习惯。遇到统计结果跟自己预期差一行的时候,先别急着怀疑数据有问题,检查一下文件末尾有没有换行符。
1.2 用awk“真正”数行数
如果确实需要把“没有结尾换行的最后一行”也算进去,用awk更准:
bash复制awk 'END{print NR}' test.txt
NR是awk处理过的记录数,默认记录分隔符是换行符,但awk对“没有换行符结尾的最后一段”也会当成一条记录。所以上面例子里的printf 'a\nb\nc'文件,awk 'END{print NR}'会输出3,而wc -l输出2。
日常使用中,我一般用wc -l做快速统计,如果怀疑文件格式特殊,再用awk 'END{print NR}'交叉验证一次。两个数字不一样,基本就是结尾换行符的问题。
1.3 空文件、Windows换行符和跨平台坑
空文件的行数统计,wc -l输出0,awk输出0,没有争议。但只有一行且没有换行符的文件就是上面说的那种边界情况。
从Windows传过来的文本文件行尾是\r\n,wc -l数\n,依然能正确统计行数。但这类文件在Linux里用grep匹配时容易踩坑。比如一个文件内容是foo\r\n,用grep '^foo$' file会匹配不到,因为行尾实际上还有一个\r字符。排查问题时如果grep怎么都匹配不上,可以先检查是不是CRLF换行:
bash复制file test.txt
看到line terminators: CRLF或者with CRLF line terminators就基本确认了。处理方式可以用dos2unix转换,或者临时用sed 's/\r$//'去掉行尾的\r再统计匹配。这类问题在统计行数时不影响结果,但配合grep、awk做条件统计时会带来很多莫名其妙的“幽灵问题”。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 需要按条件统计时,sed、awk、grep才是主力
2.1 grep -c按模式计数,但退出码是个坑
wc -l只能统计全部行数,实际工作中更多时候需要“统计满足某个条件的行数”。最常见的是grep -c:
bash复制grep -c 'ERROR' app.log
输出包含ERROR的行数。注意grep -c统计的是“匹配的行数”,不是“匹配的次数”。如果一行里出现三次ERROR,grep -c也只算一行。想数匹配次数要用grep -o 'ERROR' file | wc -l。
用grep -v可以反向统计:
bash复制grep -cv '^$' file
这个命令统计非空行数。^$匹配空行,-v取反,两个组合起来就是“不匹配空
