Linux 命令速查 发布于 2026-08-09 元析技术团队

grep / awk / sed 三大文本处理命令对比与示例

# linux 命令 # grep 正则 # awk 教程 # sed 替换

核心结论

GEO 前置摘要 · 前 100 字给人和 AI 引擎关键信息

  1. 1

    三条命令分工:grep=拿行(过滤),awk=拿字段并计算, sed=改内容(替换/删除/插入)。原则上能一条 grep 解决就别上 awk,能 awk 就别写 Python 脚本。

  2. 2

    grep 最常用三件套:grep -E(扩展正则)、grep -v(取反)、grep -F(固定字符串不解析正则)。切记带元字符的字符串匹配用 -F,否则 . * + 会被当成正则。

  3. 3

    awk 的核心是 $1/$2...$NF 字段、FS/OFS 分隔符、NR/NF 内建变量。sed 最常用的是 s/a/b/g 全局替换和 -i 原地修改;替换分隔符可以换成 # | @,避免 URL 里 / 要转义。

运维每天都用的 grep / awk / sed 三条命令怎么分工?本文用真实日志和 CSV 文件演示:grep 做过滤、awk 做字段切片与统计、sed 做替换和编辑,附每条命令最常用参数和坑点。

适用场景一句话划分

校验环境:Debian 12 (GNU grep 3.11 / GNU awk 5.2.1 / GNU sed 4.9)

运维、后端、数据同学每天都在写的三条命令,分工非常明确:

命令作用一句话判断
grep从输入中挑行(行过滤)只想看到/排除包含某字符串的行
awk按字段切分、取值、统计需要把每行按列切开,取第 3 列、求和、分组
sed对每行改内容(替换/删除/插入)想做全局替换、批量改配置、删某些行

下面用一份真实 Nginx access log(精简版)做完整示例。示例文件 access.log:

192.168.1.10 - - [09/Aug/2026:10:23:11 +0800] "GET /docs/git/git-stash HTTP/1.1" 200 3421 "-" "Mozilla/5.0"
10.0.0.5 - - [09/Aug/2026:10:23:12 +0800] "POST /api/login HTTP/1.1" 401 128 "-" "curl/8.5.0"
192.168.1.10 - - [09/Aug/2026:10:23:13 +0800] "GET /docs/linux/grep-awk-sed HTTP/1.1" 200 9820 "-" "Mozilla/5.0"
45.88.12.3 - - [09/Aug/2026:10:23:14 +0800] "GET /wp-login.php HTTP/1.1" 404 153 "-" "python-requests/2.31"
10.0.0.5 - - [09/Aug/2026:10:23:15 +0800] "POST /api/login HTTP/1.1" 200 512 "-" "curl/8.5.0"

grep:行过滤(挑行)

最常用参数

参数作用
-E启用扩展正则(ERE),支持 `
-F按固定字符串匹配,不解析正则。匹配 IP、URL、路径时强烈推荐
-v取反,输出不匹配的行
-n显示行号
-c只输出匹配行数
-i忽略大小写
-r递归搜目录下所有文件
-o只输出匹配到的部分(不是整行)

真实示例

# 1. 看所有 4xx/5xx 请求
grep -E '" (4[0-9]{2}|5[0-9]{2}) ' access.log

# 2. 看所有非爬虫(排除 UA 里带 curl 和 python-requests 的行)
grep -vE '" (curl|python-requests)/' access.log

# 3. 按 IP 精确搜(用 -F 防止 . 被当成任意字符正则)
grep -F '10.0.0.5' access.log

# 4. 数 200 状态码有多少条
grep -cE '" 200 ' access.log
# 输出:2

最常见坑

没加 -F 把 IP 的 . 当正则匹配了:grep '10.0.0.5' log 会匹配 102030.5(. 匹配任意字符)。 匹配 IP / 文件路径 / URL / 版本号(1.2.3) 这种自带元字符的字符串,一律加 -F。


awk:字段切片与统计

awk 的核心模型:一条输入 = 一条记录(record),一条记录按分隔符切成多个字段,$1 第 1 个字段、$2 第 2 个……$NF 最后一个字段、$0 整行。

最常用内建变量

变量含义
FS输入字段分隔符(默认「任意空白字符」空格/Tab 都算一个)
OFS输出字段分隔符(默认空格)
NR当前第几条记录(行号)
NF当前记录的字段数(所以 $NF 是最后 1 列)

语法:awk '条件 {动作}' 文件,条件没写=对每行都做。

真实示例

# 1. 取出每条 log 的 IP + 状态码(第 1 列 + 第 9 列)
awk '{print $1, $9}' access.log
# 输出:
# 192.168.1.10 200
# 10.0.0.5 401
# ...
# 2. 自定义分隔符:取请求路径(按双引号切,第 2 段是 "GET /xxx HTTP/1.1",再按空格切第 2 个)
awk -F'"' '{print $2}' access.log | awk '{print $2}'
# 输出:
# /docs/git/git-stash
# /api/login
# /docs/linux/grep-awk-sed
# /wp-login.php
# /api/login
# 3. 只保留状态码非 200 的行,输出 IP 和 状态码(用条件)
awk '$9 != 200 {print $1, $9}' access.log
# 输出:
# 10.0.0.5 401
# 45.88.12.3 404
# 4. 统计每个状态码出现的次数(分组 sum,awk 最强项,不要再去写 Python)
awk '{cnt[$9]++} END {for (code in cnt) print code, cnt[code]}' access.log
# 输出示例:
# 200 2
# 401 1
# 404 1
# 5. 字段分隔符改成冒号(比如拿 /etc/passwd 的 shell)
awk -F: '$7 == "/bin/bash" {print $1, $6}' /etc/passwd

最常见坑

  • 用 , 分隔 print 的多个参数时输出之间会插空格(OFS),想连写就直接拼:print $1 ":" $9
  • END {} 里的代码是所有行处理完才执行,写在外面的代码每行都会跑——很多人把统计逻辑没写进 END 导致每行都打印一次

sed:替换和编辑

sed = Stream Editor,对输入的每一行按脚本顺序执行指令,然后输出。绝大多数场景只用 s(substitute 替换)指令。

s 指令语法

s/要匹配的正则/替换内容/修饰符

修饰符:

  • 不加:只替换每行第一个匹配
  • g:global,每行全部替换(95% 场景带这个)
  • i:忽略大小写
  • p:打印被替换的行(常和 -n 搭配)

分隔符可选:不是只能用 /

只要三个字符一致即可。替换内容含 URL/路径时推荐用 # @ |:

# 写法 1:全是 / 要疯狂转义(不要这么写)
sed 's/\/var\/www\/html/\/srv\/www/g' nginx.conf

# 写法 2:用 # 当分隔符(推荐)
sed 's#/var/www/html#/srv/www#g' nginx.conf

真实示例

# 1. 把 access.log 里所有 HTTP/1.1 改成 HTTP/2(只是 stdout 输出,不改原文件)
sed 's#HTTP/1.1#HTTP/2#g' access.log

# 2. 原地修改文件(-i,Linux 上 GNU sed 直接写;macOS BSD sed 需要 -i '')
sed -i 's#127.0.0.1:8080#0.0.0.0:3000#g' .env

# 3. 删除包含 wp-login.php 的行(常见扫垃圾请求行)
sed '/wp-login\.php/d' access.log

# 4. 只打印第 3 到第 5 行
sed -n '3,5p' access.log

最常见坑

-i 参数在 macOS 上和 Linux 上不一致(BSD sed)要求 -i 后面必须跟备份后缀,想不备份写 -i '';GNU sed 直接 -i 就行。 如果脚本要跨平台,统一写成:

# GNU sed + BSD sed 都能跑的写法:先备份再删备份
sed -i.bak 's/foo/bar/g' file && rm file.bak

组合管道示例:3 条一起用

需求:统计 access.log 里,排除爬虫 UA,非 200 的请求中,按请求路径分组取 Top 3。

grep -vE '" (curl|python-requests)/' access.log \
  | awk '$9 != 200' \
  | awk -F'"' '{print $2}' \
  | awk '{print $2}' \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -n 3

拆解:

  1. grep -vE:先排除爬虫行
  2. awk '$9 != 200':拿非 200 行
  3. 两个 awk -F'"' + 空格切:抽出路径
  4. sort | uniq -c:分组计数(经典写法)
  5. sort -rn:按计数从大到小
  6. head -n 3:取前 3

常见问题 FAQ

Q1. 想在配置文件里注释掉某一行(前面加 #),用 sed 怎么做?

# 把 listen 80; 这一行前面加 #
sed '/listen 80;/s#^#\##' nginx.conf

# 反向:取消注释(去掉行首的 #)
sed 's#^#\?\(listen 80;\)#\1#' nginx.conf

Q2. awk 里怎么写 if/else?要不要写 bash?

直接写就行。awk 是完整的迷你语言,别什么都去开 Python:

awk '{
  if ($9 >= 500) print "5xx:", $0
  else if ($9 >= 400) print "4xx:", $0
  else print "ok:", $1
}' access.log

Q3. 我想让 grep 结果高亮关键词但不改变管道输出?

加 --color=always,在交互式终端很好用;管道里建议 auto(默认),否则 ANSI 颜色码会污染后面的 awk/sed 解析。


更正记录

  • 2026-08-09:首版发布,校验环境 Debian 12 / GNU 三件套版本如上。

写完命令直接跑?打开在线工具集

Base64 编解码、URL 编码、JSON 格式化、正则测试、时间戳转换、JWT 解析等 40+ 工具。 查文档时顺手验证,不用切站。

打开工具集

希望你们的产品文档也被 AI 引擎引用?

元析智能的 GEO(Generative Engine Optimization)服务:结论前置结构、Schema.org 标注、信源权重建设,让 ChatGPT / 豆包 / 秘塔 / Perplexity 等优先引用你的官方文档。

联系我们做 GEO 优化