这个命令是干啥的
wc(Word Count) 是 Linux 里最朴素也最常用的命令之一。它的本职工作就是"数数",数文件里有多少行、多少个单词、多少个字节。
我刚开始工作时觉得 wc 没啥技术含量,不就是 wc -l 看行数嘛。后来慢慢发现,wc 在脚本和日常工作中的出场率极高:统计代码行数、检查日志有没有新内容、确认文件是否为空、配合管道取数据总量……样样离不开它。
简单、可靠、不整花活,这就是 wc 的风格。
基本用法(3分钟上手)
默认输出
# 不带选项,输出三列:行数、单词数、字节数
wc file.txt
150 820 5640 file.txt
三列分别是:150行、820个单词、5640个字节。
常用选项
# 只统计行数(最常用)
wc -l file.txt
# 只统计单词数
wc -w file.txt
# 只统计字符数(中文友好)
wc -m file.txt
# 只统计字节数
wc -c file.txt
# 统计最长行的长度
wc -L file.txt
-L 这个选项我得说下,它输出文件中最长那一行的字符数(含换行符)。这个在排查文本格式问题时挺有用。
统计多个文件
# 同时统计多个文件,最后会有一行合计
wc -l file1.txt file2.txt file3.txt
输出类似:
150 file1.txt
200 file2.txt
180 file3.txt
530 total
最后的 total 行很方便,不用自己再加一遍。
从管道接收输入
# 统计 ls 输出了多少行(等价于 ls | wc -l)
ls | wc -l
# 统计当前目录下有多少个文件
ls -l | grep '^-' | wc -l
wc -l 在管道末尾非常常用,它就像一个计数器,告诉你上一条命令输出了多少行。
进阶骚操作
统计项目代码行数
找项目里有多少行代码,我是这么玩的:
# 统计当前目录下所有 .py 文件的行数
find . -name "*.py" -exec wc -l {} +
# 或者用 xargs
find . -name "*.go" | xargs wc -l
-exec wc -l {} + 这个写法会把所有找到的文件一次传给 wc,最后自动出一行 total。比写循环再手动 sum 方便多了。
排除空行和注释
纯粹统计代码行数时,直接 wc -l 会连空行和注释一起算。我经常这么搞:
# 排除空行
grep -v '^$' file.py | wc -l
# 排除空行和以 # 开头的注释行
grep -v -E '^\s*$|^\s*#' file.py | wc -l
有一次老板问我"这个模块一共多少行有效代码",我就是用这个组合秒回的,印象中那是个 5000 行的大文件,过滤掉空行和注释后还剩 3800 多行。
配合 git 统计工作量
# 统计某个开发者提交的代码行数变更
git log --author="张三" --pretty=tformat: --numstat | awk '{add+=$1; del+=$2} END {print "新增:", add, "删除:", del}'
# 统计最新一次提交改了多少文件、多少行
git diff --stat HEAD~1 HEAD | tail -1
# 统计当前分支比 main 分支多了多少行
git diff --stat main..HEAD | tail -1
我面试的时候被问过"怎么用 git 统计代码量",虽然用到的不是 wc 而是 git 自身的 --stat,但背后的思想和 wc 一样,就是数数和汇总。
wc -L 查最长行
# 看 config 文件里有没有超长的行
wc -L nginx.conf
# 配合 find 找出项目中超长行的文件
find . -name "*.css" -exec wc -L {} + | sort -rn | head -5
这招排查过一个问题:某个 CSS 文件里有一行 base64 编码的字体文件,长度超过 30000 个字符,导致构建工具直接崩了。wc -L 一查就定位到。
配合别的命令做校验
# 检查下载文件的行数是否和预期一致
expected=1500
actual=$(wc -l < data.csv)
if [ "$actual" -eq "$expected" ]; then
echo "行数一致,继续处理"
else
echo "文件不完整,预期 $expected 行,实际 $actual 行"
fi
避坑指南
坑1:wc -l 数的是换行符数量,不是严格的行数
如果文件最后一行没有换行符,wc -l 会少算一行:
# 创建一个没有末尾换行的文件
printf "hello\nworld" > test.txt
wc -l test.txt # 输出 1,不是 2
很多编辑器(特别是 Windows 过来的)会在最后自动加换行,但有些工具不会。我遇到过从 API 下载的 CSV 文件最后一行没换行,wc -l 的结果和我想的不一样,排查了半天才发现是这个原因。
坑2:wc -c 和 wc -m 在中英文混排时不一样
# 中文一个字符占多个字节
echo "你好" | wc -c # 输出 7(含换行符,UTF-8中"你好"占6字节)
echo "你好" | wc -m # 输出 3(含换行符,字符数)
需要区分"字节数"和"字符数",这在处理中文文本时特别重要。
坑3:wc -L 统计的是"显示宽度"还是"字符数"?
wc -L 统计的是字符数(不是字节数),但不会计算零宽字符的宽度。中文字符按1个字符算,不是按显示宽度2算。如果你在意的是"这一行在终端里占了多宽",wc -L 不够准确,需要用 awk 加 strlen 来处理。
坑4:管道里用 wc -l 要加 < 还是 |?
# 这两种写法结果一样,但方式不同
wc -l < file.txt # 从文件重定向
cat file.txt | wc -l # 从管道读
第一种少开一个 cat 进程,稍微高效一点。脚本里我倾向用 < 重定向。
实战场景(重点!结合真实运维场景)
场景1:监控日志增长
上线新版本后,我经常要盯着日志量有没有异常增长:
# 每10秒看一次 access.log 的行数
watch -n 10 'wc -l /var/log/nginx/access.log'
# 对比前一分钟的行数差值,算每秒请求量
prev=$(wc -l < /var/log/nginx/access.log)
sleep 60
curr=$(wc -l < /var/log/nginx/access.log)
echo "每秒请求量: $(( (curr - prev) / 60 ))"
有一回线上突然 QPS 翻了三倍,我用这个脚本一跑发现每秒请求量从 200 涨到了 600,赶紧去排查,后来发现是被爬虫盯上了。
场景2:统计项目代码量
想看看自己项目总共写了多少行:
# 统计 Java 项目(排除 .git、target 目录)
find . -name "*.java" -not -path "./.git/*" -not -path "./target/*" | xargs wc -l | tail -1
# 统计多种文件类型
find . \( -name "*.py" -o -name "*.js" -o -name "*.html" \) -not -path "./node_modules/*" | xargs wc -l | tail -1
我给客户报工作量的时候经常用这个,虽然行数不代表质量,但至少是个量化指标。
场景3:检查备份文件完整性
数据库备份完后,我会检查文件大小和行数:
# 确认 SQL 备份文件的行数和大小
echo "行数: $(wc -l < backup.sql)"
echo "大小: $(ls -lh backup.sql | awk '{print $5}')"
echo "字符数: $(wc -c < backup.sql)"
如果两次备份的行数差异很大,说明数据可能有异常。我遇到过备份脚本中途失败只备份了一半的情况,就是靠比对行数发现的。
场景4:日志分割校验
日志轮转后,验证新日志是否正常写入:
# 等1分钟看新日志文件有没有增长
old=$(wc -c < /var/log/myapp/current.log)
sleep 60
new=$(wc -c < /var/log/myapp/current.log)
if [ "$new" -gt "$old" ]; then
echo "日志正常写入"
else
echo "警告:日志没有增长,应用可能挂了"
fi
这个脚本在我写的监控工具里存活了好几年,简单但管用。
今日作业
在任意一个有代码的项目目录下(没有就创建一个),完成以下任务:
1. 统计目录下所有 .py(或 .js 或 .go 等)文件的代码总行数
2. 统计排除空行后的有效行数
3. 找出项目中行数最多(wc -L 最大)的那个文件是哪一行
用一条 find + xargs + wc 的组合命令完成。试试看能不能一次搞定。