sed/awk/grep 文本处理速查表 - Linux 文本处理命令大全

日志排障和报表统计几乎都是三段式:grep 捞出关心的行,sed 改掉要改的值,awk 按列汇总。这张表按这三条链路分组,再往外扩出组合管道、sort/uniq/comm 的排序去重与对比、cut/tr/paste 的列与字符处理。定位差异比命令本身重要:grep 是行级筛选,行内任意位置匹配;sed 是流编辑器,逐行替换插入删除,适合格式统一;awk 是列级处理器,只有它能按列累加、分组计数、排序输出。选错工具就要绕远路——统计各 IP 出现次数用 awk 一步到位,用 grep 加 wc -l 则要跑 N 次。判断依据落在两处:大文件时 grep 要加 --line-buffered 否则下游迟迟不出结果,awk 在双引号里必须把 $1 写成 \$1。

系统与运维·共 52 条命令·最后更新 2026-07-21
sedawkgrep文本处理正则

典型使用场景

面向做日志排障与报表统计的开发者:grep 定位、sed 改写、awk 按列汇总、sort/uniq 去重计数,四者用管道串成链路,就能覆盖日常八成的文本处理需求。关键是分清三者分工:grep 按行筛,sed 按行改或按行删,awk 按列取数与计算。把它们混用(比如用 grep 去列取数)是新手最常见的效率损失。本表按这五条链路组织,可直接当排错手册用。

grep 匹配与搜索 10

grep "error" app.log
查找包含 error 的行
grep -i "error" app.log
忽略大小写匹配
grep -rn "TODO" src/
递归搜索目录,显示文件名和行号
grep -v "debug" app.log
反向匹配,排除含 debug 的行
grep -c "error" app.log
统计匹配行数
grep -E "error|warning" app.log
扩展正则,等价于 egrep
grep -oE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" access.log
只输出匹配的 IP 地址部分
grep -A 3 "error" app.log
匹配行后再显示 3 行上下文
grep -B 2 "error" app.log
匹配行前显示 2 行上下文
grep -f pattern.txt app.log
从文件读取多个模式

sed 替换与编辑 9

sed 's/old/new/g' file.txt
全局替换 old 为 new
sed -i 's/old/new/g' file.txt
直接修改文件(原地编辑)
sed -i.bak 's/old/new/g' file.txt
修改文件并备份原文件为 .bak
sed '5d' file.txt
删除第 5 行
sed '/^#/d' file.conf
删除所有以 # 开头的注释行
sed '/^$/d' file.txt
删除空行
sed -n '10,20p' file.txt
只打印第 10-20 行
sed 's/[[:space:]]*$//' file.txt
删除行尾空格
sed -E 's/([0-9]+)/\1/' file.txt
扩展正则捕获组,-E 等价于 -r

awk 提取与统计 9

awk '{print $1}' access.log
打印第一列(默认空格分隔)
awk -F: '{print $1, $3}' /etc/passwd
指定冒号分隔,打印用户名和 UID
awk 'NR==10' file.txt
打印第 10 行(NR=行号)
awk 'NR>=10 && NR<=20' file.txt
打印第 10-20 行
awk '{sum += $1} END {print sum}' nums.txt
对第一列求和
awk '{count[$1]++} END {for(k in count) print k, count[k]}' access.log
按第一列分组统计出现次数
awk '$3 > 100' data.txt
打印第三列大于 100 的行
awk 'length > 80' file.txt
打印长度超过 80 的行
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
列出 UID >= 1000 的普通用户

组合管道 Pipeline 4

grep "error" app.log | awk "{print \$1}" | sort | uniq -c | sort -rn | head
统计 error 日志中每个时间戳出现次数 TOP
cat access.log | awk "{print \$1}" | sort | uniq -c | sort -rn | head -20
统计访问量 TOP 20 的 IP
grep -oE "[0-9]+ms" app.log | sort -rn | head -10
提取响应耗时 TOP 10
sed '/^#/d; /^$/d' nginx.conf
一次删除注释行和空行(多条命令用分号)

sort / uniq / comm 排序去重与对比 10

sort file.txt
对文件内容排序(默认按字典序)
sort -n file.txt
按数值大小排序
sort -r file.txt
逆序排序
sort -t: -k3 -n /etc/passwd
按冒号分隔的第 3 列数值排序
sort -u file.txt
排序并去重
sort file.txt | uniq -c | sort -rn | head
经典组合:统计各行频率 TOP
uniq -c file.txt
统计每行重复次数(需先 sort)
uniq -d file.txt
只显示重复的行
comm file1 file2
比较两个已排序文件,三列:仅 file1/仅 file2/共有
diff -u file1 file2
统一格式比较文件差异

cut / tr / paste 列与字符处理 10

cut -d: -f1 /etc/passwd
按冒号分隔提取第 1 列
cut -c1-10 file.txt
按字符位置截取第 1-10 个字符
cut -f1,3 file.txt
提取第 1 和第 3 列(默认 Tab 分隔)
tr 'a-z' 'A-Z' < file.txt
小写转大写
tr -d ' \t' < file.txt
删除所有空格和 Tab
tr -s '\n' < file.txt
压缩连续空行为单个换行
paste file1.txt file2.txt
按列合并两个文件(默认 Tab 分隔)
column -t file.txt
将内容对齐为表格格式输出
expand file.txt
将 Tab 转换为空格
command | tee output.txt
同时输出到屏幕和文件(常用于管道)

参数矩阵

参数作用示例
grep -r / -R递归搜索;大写 R 额外跟随符号链接grep -rn "TODO" src/
grep -i / -v忽略大小写 / 反向排除grep -iv "debug" app.log
grep -C <n>显示匹配行前后各 n 行上下文grep -C 3 "error" app.log
grep -o只输出匹配部分而非整行grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' access.log
sed -i.bak原地编辑并留 .bak 备份sed -i.bak 's/old/new/g' f.txt
sed 's/a/b/g'全局替换;不加 g 只换每行第一个sed 's/localhost/0.0.0.0/g' c.yaml
sed '/pat/d'删除匹配行sed '/^#/d' nginx.conf
awk -F<sep>指定字段分隔符awk -F: '{print $1, $3}' /etc/passwd
awk $n / $NF第 n 列 / 最后一列awk '{print $1, $NF}' f.txt
awk NR / NF当前行号 / 当前行列数awk 'NR>=10 && NR<=20' f.txt
sort | uniq -c | sort -rn去重计数并按数值降序awk '{print $1}' access.log | sort | uniq -c | sort -rn
cut -d -f按分隔符取固定列cut -d: -f1 /etc/passwd

易错点与避坑指南

现象uniq 去重后结果不对,重复项还在。

原因uniq 只比较相邻行,没有先 sort 让相同内容聚到一起。

处置必须写成 sort file | uniq -c,或用一步到位的 sort -u。

现象sed 改完文件后想撤回,但内容已经变了。

原因用了 sed -i 直接原地编辑且没留备份。

处置改用 sed -i.bak 留 .bak;或先不带 -i 跑一遍确认输出再落盘。

现象grep 明明搜不到实际存在的字符串。

原因大小写不匹配,或模式里的元字符被当正则解释。

处置加 -i;搜字面量用 -F(搜 a.b 会连 axb 一起命中)。

现象用 awk 取到的列全是空的。

原因分隔符不匹配——文件是冒号分隔却没加 -F:,awk 默认按空白切,整行成了一个字段。

处置用 awk -F: 指定分隔符;先用 head 看一眼真实分隔符再写表达式。

现象统计出的 IP 数量不对,每行被算成一次。

原因用 grep -o 提取时漏了管道,或没用 -o 导致 uniq 统计的是整行。

处置grep -oE "模式" file | sort | uniq -c | sort -rn,-o 不能省。

现象sed 替换后文件变成了空。

原因分隔符 / 与模式中的路径冲突,或误用了 d 而非 s。

处置含 / 时改用 # 作分隔符;执行前先不带 -i 看输出。

排障路径

  1. 1先看原始数据长什么样再写表达式

    head -3 access.log

    确认分隔符与列的位置,能避免大部分「awk 取不到列」的返工。

  2. 2统计访问量 TOP 20

    awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

    取列 → 排序让相同值相邻 → 计数 → 按数值降序,四步缺一不可。

  3. 3带上下文定位报错

    grep -n -C 3 "FATAL" app.log

    -n 给行号、-C 3 前后各三行,通常这几行就说明了问题。

  4. 4改文件前先干跑确认

    sed 's/old/new/g' config.yaml

    不加 -i 只输出;确认无误后再用 sed -i.bak 落盘。

  5. 5一次清理注释与空行

    sed '/^#/d; /^$/d' nginx.conf

    多条命令用分号分隔,一次扫描完成。

命令示例

统计访问量最高的 20 个 IP

awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20

awk 取第一列,sort 让相同值相邻,uniq -c 计数,sort -rn 按数值降序——四步缺一不可,直接 uniq 会因为行不相邻而失效。

输出

   1842 203.0.113.7
    931 198.51.100.22
    407 192.0.2.180

只提取 5xx 错误对应的 URL

awk '$9 ~ /^5/ {print $7}' access.log | sort | uniq -c | sort -rn

标准 combined 日志格式里第 9 列是状态码、第 7 列是请求路径,所以条件直接落在第 9 列上。比 grep 整行后再切分快得多。

输出

     87 /api/orders
     34 /api/checkout
     12 /api/login

删除配置里的注释行与空行

sed '/^#/d; /^$/d' nginx.conf

sed 的多条命令用分号分隔,可以在一次扫描里完成。配合 -i.bak 就能原地改文件且留有备份。

输出

worker_processes auto;
events {
    worker_connections 1024;
}

改文件前先干跑一遍确认替换结果

sed 's#http://#https://#g' config.yaml

先把 / 换成 # 作分隔符,避免 URL 里的斜杠与 sed 的分隔符冲突。不加 -i 只输出不改文件,确认无误后再加 -i.bak 落盘。

常见坑与注意事项

  • sed -i 直接改文件且无备份,改错无法回退;先用不带 -i 的版本确认输出,再用 -i.bak 留后路。
  • sed 默认是 BRE,\+ \| \( 在基本正则里不是特殊字符,需要 -r 切到扩展正则。
  • grep 搜索含 / 的 URL 路径会与分隔符冲突,改用 # 作分隔符。
  • uniq 只比较相邻行,不先 sort 就用会漏掉分散在文件各处的重复项。
  • awk 的 $1 从 1 开始,与数组下标习惯不同;$0 是整行,$NF 是最后一列。
  • cut 不支持多字符分隔符,也不做任何计算,遇复杂分隔或需统计时应换 awk。

提示

  • sed -i 直接修改文件前先备份(-i.bak),或先不加 -i 预览结果再写入。
  • grep 处理大文件加 --line-buffered 让输出实时刷新,否则管道下游会等缓冲满。
  • awk 单引号内用 $1 取列,双引号内要转义为 \$1,否则 shell 会解释。
  • awk -F"|" 把管道符当分隔符统计时,若字段本身可能含 |,改用 -F"[|]" 之外的方案或先 gsub 处理,否则列号会错位。
  • sort -u 与 uniq 的区别在于 sort -u 去重的是整行排序后的结果,uniq 只去相邻重复,所以 uniq 前必须先 sort。
  • join 要求两个输入文件都按连接字段排序且分隔符一致,先各自 sort -t" " -k2 才能得到正确结果。

常见问题

grep、sed、awk 三者在日志排障里该怎么配合?

典型链路是「先筛后改再汇总」:用 grep -i "error" app.log 把关心的行筛出来,用 sed -n '/^#/d' file 之类的规则先清掉噪声,再用 awk 按列汇总。比如统计 TOP 报错就用 grep "error" app.log | awk "{print $1}" | sort | uniq -c | sort -rn | head。grep 负责定位,sed 负责改写和按行筛选,awk 负责按列取数与统计,三者用管道串起来比分写脚本快得多。

sed -i 原地修改文件太危险,怎么降低改错的代价?

先用 sed -i.bak '/s/old/new/g' file.txt 做原地编辑并自动留下 .bak 备份,确认无误后再删备份;或者先不带 -i 跑一遍 sed 's/old/new/g' file.txt 只看输出,确认替换结果符合预期后再决定是否落盘。这两步习惯能避免绝大多数不可逆的误改。

awk 里 $0、$1、NR、NF 分别代表什么?

$0 是整行内容,$1 $2 是按分隔符切出的第几列($NF 是最后一列),NR 是当前行号,NF 是当前行的列数,它们都是 awk 的内置变量,不需要声明即可使用。例如 awk '{print NR, $1}' file 会同时输出行号和第一列,awk 'NR>=10 && NR<=20' file 则只处理第 10 到 20 行。

为什么 sort -u 和 uniq 要配合 sort 一起用?

uniq 只比较相邻的两行,去重依赖「相同内容已经相邻」这个前提;而 sort 默认把内容排序,同值行自然聚到一起。所以正确写法是 sort file.txt | uniq -c,或用一步到位的 sort -u file.txt。如果不先排序直接 uniq,重复行分散在文件各处就永远识别不出来。

cut 和 awk 都能取列,什么时候用哪个?

cut -d: -f1 /etc/passwd 处理「按单个字符分隔、取固定几列」最快,输出也干净;但它不认多字符分隔符,也不做任何计算。awk -F: '{print $1, $3}' /etc/passwd 更灵活:能设多字符分隔、能按列做条件判断和求和统计。规则很简单——只是取几列用 cut,一旦涉及计算或复杂分隔就用 awk。

官方参考来源

下方为命令对应的官方权威文档,供你核对最新用法与深入查阅。

由 巧匠 维护

公开更新于 2026年7月21日,内容持续校对官方文档。

联系我们

命令或描述有误?提交反馈、商务合作或产品建议都可发送邮件给我们。

联系我们