这个场景解决什么
拿到一个 CSV,想快速知道「这一列都有哪些取值、各出现多少次、金额合计多少」,用 awk 加 sort 加 uniq -c 只要一条管道就能出结果。流程是三步:先看表头确认列号,再用 awk 抽出目标列或直接做聚合,最后排序取排行。前提是字段里没有带逗号的引号字段——那属于真正的 CSV,得用能解析引号的工具。
基本信息
| 场景 | CSV 的单列分布统计与数值汇总 |
|---|---|
| 工具组合 | awk -F, 抽列与聚合、sort 排序、uniq -c 计数、sort -rn 排行 |
| 必要前提 | 字段内不含分隔符;先看表头确定列号,并跳过表头行 |
| 适用规模 | 单机几十万到数百万行都能胜任,更大规模再考虑数据库 |
典型使用场景
- 分布核对:订单表里各渠道的订单量占比,快速判断数据是否符合预期
- 异常筛查:某个地区或状态的记录数异常偏多,作为进一步排查的入口
- 数值汇总:金额、数量字段的合计与均值,用于对账前的粗校
- 分组透视:按维度分组求和,输出成可直接粘贴到报表的清单
- 数据清洗前评估:先看缺失值与异常取值的分布,再决定清洗规则
列分布与排行
列分布与排行
head -1 sales.csv # 先确认列号
awk -F, 'NR>1 {print $3}' sales.csv | sort | uniq -c | sort -rn | head -20
awk -F, 'NR>1 {cnt[$3]++} END {for (k in cnt) printf "%8d %s\n", cnt[k], k}' sales.csv | sort -rn | head数值汇总与分组透视
数值汇总与分组透视
awk -F, 'NR>1 {n++; s+=$5} END {printf "行数=%d 合计=%.2f 均值=%.2f\n", n, s, s/n}' sales.csv
awk -F, 'NR>1 && $5 ~ /^[0-9.]+$/ {n++; s+=$5; if ($5>mx||n==1) mx=$5; if ($5<mn||n==1) mn=$5} END {printf "n=%d sum=%.2f min=%.2f max=%.2f\n", n, s, mn, mx}' sales.csv
awk -F, 'NR>1 {s[$2]+=$5} END {for (k in s) printf "%-12s %.2f\n", k, s[k]}' sales.csv | sort -k2 -rnCSV 处理工具选择
| 工具 | 适合 | 限制 |
|---|---|---|
| awk -F, | 字段简单、无内含逗号的大文件 | 不支持引号转义,脏数据会切错列 |
| cut -d, | 纯抽列,不做计算 | 同样不处理引号与转义 |
| python3 csv 模块 | 字段含引号、换行的标准 CSV | 需要写几行代码,适合复杂清洗 |
| csvkit(csvstat/csvcut) | 需要列统计与规范化输出 | 需额外安装,处理超大文件偏慢 |
| miller(mlr) | 需要按列名做分组聚合 | 需额外安装,语法自成体系 |
字段里带英文逗号或引号的「真 CSV」不能用 -F, 硬切:切出来的列是错的,统计结论也就全错。用多行样例先跑一次,看列数是否稳定,是不错的快速自检。
两个固定套路:NR>1 跳过表头,否则统计里会多出一行;列号从 1 开始数,以 head -1 的实际输出为准,不要凭记忆。