这个命令是干啥的
sort 和 uniq,两个命令,但工作中几乎永远一起用。
sort 就是排序。把文件的行按字母顺序、数字大小、或者某列重新排好。uniq 是去重,把连续重复的行只留一个。注意是"连续重复"这四个字,如果重复的行不挨着,uniq 不会去重。所以 uniq 前几乎必加 sort。
这两个命令组合起来就是一套完整的"分组统计"方案。运维写日报、统计日志、看排行榜,全靠它们。
我最早学的时候觉得 sort 就只是排序,uniq 就只是去重,太简单了吧?后来发现这哥俩组合起来能干的事真不少,特别是 uniq -c 加 sort -rn 这个组合,可以算是我用过次数最多的 Linux 命令管道了。
基本用法(3分钟上手)
sort 基础
先创建一个测试文件:
# 创建测试文件
cat > fruits.txt << 'EOF'
banana
apple
orange
apple
grape
banana
EOF
# 默认按字母升序排序
sort fruits.txt
输出:
apple
apple
banana
banana
grape
orange
sort 常用选项
# 按数字大小排序(默认是字典序,10会排在2前面)
sort -n numbers.txt
# 倒序
sort -r fruits.txt
# 去重后再排序(相当于 sort | uniq)
sort -u fruits.txt
# 忽略大小写
sort -f fruits.txt
sort -u 是个好文明,它等于先 sort 再 uniq,一步到位。
uniq 基础
# 去重(只保留不连续的重复行中的第一个)
uniq fruits.txt
# 统计每行出现次数
uniq -c fruits.txt
# 只显示重复行
uniq -d fruits.txt
# 只显示不重复的行
uniq -u fruits.txt
注意看,因为我们的 fruits.txt 里的 apple 和 banana 本来是连续的重复,但 sort 之后它们被分开了,所以你得先 sort 再 uniq:
# 正确姿势:先排序再去重
sort fruits.txt | uniq
进阶骚操作
按列排序
处理表格数据时最常用:
# 假设成绩单按第3列(分数)排序
cat > scores.txt << 'EOF'
张三 语文 85
李四 数学 92
王五 语文 78
张三 数学 95
EOF
# 按第3列数字排序(-k 指定列,-n 按数字)
sort -k3 -n scores.txt
# 按第3列倒序(最高分在前)
sort -k3 -rn scores.txt
# 指定分隔符(默认空格),按第2列排序
sort -k2 scores.txt
sort + uniq -c 统计频率
这是最经典组合,生成频率报表:
# 统计每个水果出现次数
sort fruits.txt | uniq -c
输出:
2 apple
2 banana
1 grape
1 orange
按频率排序(从高到低)
# 统计 + 按次数倒序,一条管道搞定
sort fruits.txt | uniq -c | sort -rn
2 banana
2 apple
1 orange
1 grape
注意 sort -rn 在管道末尾的作用,它按第一列(也就是频次)的数字倒序排。这就是排行榜的诞生方式。
sort -t 指定分隔符
如果文件不是空格分隔,用 -t:
# 处理 CSV 文件,按第2列的数值排序
sort -t',' -k2 -n data.csv
sort 的"人类可读"排序
处理带单位的数字,比如 ls -lh 的结果(5.3K、102M 这种):
# 对 ls -lh 按文件大小排序
ls -lh | sort -h -k5
-h 选项能理解 K、M、G 这些单位,这让日常查大文件方便很多。
避坑指南
坑1:sort 的字典序坑死人
没有 -n 的时候 sort 按字典序排列数字:
echo -e "2\n10\n1\n20" | sort
输出是:
1
10
2
20
因为"10"的第一个字符"1"比"2"小。一定要加 -n:
echo -e "2\n10\n1\n20" | sort -n
坑2:uniq 只去连续重复
这是新手最容易踩的坑:
echo -e "a\nb\na" | uniq
结果是 a b a,因为两个 a 中间隔着 b,不连续。必须先排序:
echo -e "a\nb\na" | sort | uniq
坑3:sort 默认整行排序,按列排序要指定
有时候你以为 sort -k2 是按第2列排,但 sort 在第一列相同的情况下还是会继续比较后面的列。想要只按某列排且不关心后续,加上 -s(稳定排序)或者了解 sort 的键值语法。最稳妥的方法是用 -k2,2 表示"从第2列开始,到第2列结束":
# 只按第2列排序,不比较其他列
sort -k2,2 scores.txt
# 先按第2列排,相同再按第3列倒序
sort -k2,2 -k3,3rn scores.txt
这个 -k 的写法 start,end 我当年也记了好久,记住就行了。
坑4:uniq -c 输出左边有空格
uniq -c 默认会在计数值前面加空格对齐。如果想去掉多余空格,用 sed 或 awk 再处理一下:
sort fruits.txt | uniq -c | awk '{print $1, $2}'
实战场景(重点!结合真实运维场景)
场景1:统计 Nginx 日志中访问最多的 IP
这是运维最常做的操作,查谁在刷你的服务器:
# 提取IP列,排序去重计数,按访问量倒序取前10
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
输出示例:
54321 192.168.1.100
12345 10.0.0.55
9876 203.0.113.42
看到第一个 IP 刷了5万多次,基本可以确定在搞事,直接 iptables 封了。
有一次我线上服务器半夜 CPU 飙高,查了 top 看不出啥问题,就是用这条命令发现某个 IP 在疯狂刷接口,封掉之后 CPU 立马降下来。这一套组合拳救过我好几次。
场景2:统计 HTTP 状态码占比
# 查看访问日志中的状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
98000 200
1200 304
500 404
50 502
如果 502 或者 404 排前面,说明网站出问题了。我曾经用这个来快速判断发布后有没有引入新的错误。
场景3:分析日志中的用户操作频率
之前做一个用户行为分析,日志格式是 时间 用户ID 操作:
# 统计每个用户的操作次数,取 top 5
awk '{print $2}' user_actions.log | sort | uniq -c | sort -rn | head -5
场景4:找出日志中重复出现的错误消息
# 从 error.log 中找出重复次数最多的错误
grep "ERROR" app.log | sort | uniq -c | sort -rn | head -10
这帮我找到过一个循环报错的问题,同一个错误一秒刷几百次,日志文件半天就几十 GB。
场景5:按月份统计访问量
配合 awk 截取日期字段:
# 从日志中提取月份,统计每月请求量
awk '{print $4}' /var/log/nginx/access.log | cut -d'/' -f3 | sort | uniq -c | sort -rn
今日作业
有一个日志文件 server.log,每行格式如下:
2026-06-22 08:10:15 INFO 用户 1001 登录成功
2026-06-22 08:11:23 ERROR 数据库连接超时
2026-06-22 08:12:01 INFO 用户 1002 登录成功
2026-06-22 08:12:45 ERROR 数据库连接超时
2026-06-22 08:15:30 INFO 用户 1001 登出
2026-06-22 08:16:10 ERROR 数据库连接超时
请用 sort 和 uniq 完成:
1. 统计每种日志级别(INFO、ERROR)出现的次数
2. 按出现次数从高到低输出
提示:awk 提取第3列作为级别,管道给 sort | uniq -c | sort -rn。