当前位置:首页>Linux>linux运维三剑客·(grep / sed / awk)

linux运维三剑客·(grep / sed / awk)

  • 2026-09-21 12:09:57
linux运维三剑客·(grep / sed / awk)

linux运维三剑客·(grep / sed / awk)

这仨老家伙从70年代活到现在,不是因为怀旧,是因为真特么好用。进容器里不一定有Python,但一定有它们。以下全是干活时磨出来的经验,不带水分。


1. grep —— 找东西的

基本操作

grep "error" app.log          # 找errorgrep -i "error" app.log       # 不分大小写grep -n "error" app.log       # 告诉你哪一行

常用参数(记这5个就够了)

  • -C 5  :显示匹配行的上下5行(看报错必须带上下文)
  • -v   :反选,比如 grep -v "health" 把健康检查那堆垃圾过滤掉
  • -c   :只输出行数,grep -c error 数数今天崩了几次
  • -r   :递归搜目录,grep -r "listen 80" /etc/nginx/
  • -o   :只输出匹配到的部分,不输出整行(配合正则提取IP)

实战场景

1. 实时看日志,屏蔽噪音

tail -f app.log | grep -v "heartbeat" | grep -v "metrics"

用两个 -v 把烦人的心跳和监控刷屏过滤掉。

2. 找出所有包含旧IP的配置文件,只显示文件名

grep -rl "192.168.1.1" /etc/nginx/

-l 不显示内容,只显示文件名,专门喂给 xargs 用。

3. 从乱七八糟的日志里只提取IP地址

grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" access.log | sort | uniq -c

-E 启用扩展正则,-o 只吐出IP,后面跟个 sort | uniq -c 直接统计访问量。

4. 看报错时一定要带上下文

grep -C 5 "OutOfMemoryError" catalina.out

别光搜那一行,真正的原因往往在前面三行。

踩坑提醒

  • 用 +、?、| 这些正则符号时,记得 grep -E,不然匹配不到别怪我没说。
  • 想搜 error 但不想搜 error.log 这种文件名?用 --exclude 或 --include 指定文件类型。

2. sed —— 改东西的(不用vim)

核心心法

sed 就是流式编辑器,一行一行处理,不打开文件也能改。

替换(最常用)

sed -i 's/old/new/g' file
  • -i 直接改原文件,危险
  • 不加 -i 会输出到屏幕,可以先预览效果
  • 加后缀备份:sed -i.bak 's/old/new/g' file,改完后多一个 file.bak

替换的几种变形:

sed 's/old/new/' file       # 只替换每行第一个匹配sed 's/old/new/2' file      # 替换每行第二个匹配sed 's/old/new/g' file      # 替换所有匹配

删除行

sed -i '/^$/d' file         # 删除空行(^$ 表示空行)sed -i '/debug/d' file      # 删除所有带debug的行sed -i '5d' file            # 删除第5行sed -i '5,10d' file         # 删除5到10行

插入行

sed -i '1i # 这是第一行' file          # 在第一行前面插入sed -i '$a # 这是最后一行' file         # 在最后一行后面追加sed -i '/server {/a\    listen 80;' nginx.conf   # 匹配到server { 就追加一行

注意 a 和 i 后面的反斜杠和空格不能错,多行插入有固定格式,但上面这种单行用法最常用。

替换整行

sed -i '/^old_host=/c\new_host=10.0.0.1' .env

找到以 old_host= 开头的行,整行替换成 new_host=10.0.0.1。

多命令组合

sed -i -e 's/foo/bar/g' -e '/^$/d' file

用 -e 可以接多个操作。

踩坑提醒

  • macOS 的 sed 跟 Linux 不一样:-i 后面必须跟备份后缀,哪怕空也得写 -i ''。
  • 替换路径时,分隔符 / 跟路径冲突,可以用 # 或 | 代替,比如 sed -i 's|/old/path|/new/path|g',省得满屏反斜杠。
  • 永远先用不带 -i 的命令试一把,我见过同事把 nginx.conf 改没了,当场想拔服务器电源。

3. awk —— 切东西的(按列处理)

入门心法

很多人看到 {} 就头疼,其实你只需要记住:

  • $1 第一列,$2 第二列……$0 整行
  • 默认按空格/tab切分,连续空格算一个
  • 可以加条件,可以加统计

基本切片

awk '{print $1, $3}' access.log          # 打印第1列和第3列awk -F':''{print $1, $3}' /etc/passwd   # 用冒号分隔

带条件过滤

awk '$9 >= 400 {print $1, $9}' access.log           # 状态码>=400的awk -F':''$3 >= 1000 {print $1}' /etc/passwd       # UID>=1000的用户awk '/error/ {print NR, $0}' app.log                # 类似grep,还带行号

统计与聚合(SQL的GROUP BY)

# 统计每种状态码出现次数awk '{count[$9]++} END {for(code in count) print code, count[code]}' access.log# 统计每个IP的访问量awk '{ip[$1]++} END {for(i in ip) print i, ip[i]}' access.log | sort -rn -k2 | head

count[$9] 是个数组,每遇到一个状态码就加1,最后在 END 块里打印。

数学计算

# 计算响应时间的总和、平均、最大awk '{sum += $NF; if($NF>max) max=$NF} END {print "总时间:", sum, "平均:", sum/NR, "最大:", max}' access.log

$NF 是最后一列,不管它具体在第几列,反正就是最后一个字段。

多分隔符

# 日志格式:2023-10-01 10:23:45 [INFO] message# 用空格和方括号作为分隔符,提取级别awk -F'[ []+]''{print $4}' app.log

[ []+] 意思是匹配 [ 或 ] 或空格,多个连续分隔符会被当做一个。

格式化输出

awk -F':''{printf "%-20s %5d\n", $1, $3}' /etc/passwd

printf 可以对列对齐,适合生成报告。

踩坑提醒

  • awk 的字段索引从 1 开始,$0 是整行,别写成 $1 当整行使。
  • 默认分隔符是空白(空格或tab),如果字段间有多个空格,awk 会自动压缩成一个,一般没问题。但如果想严格按单个字符分割,用 -F' ' 指定空格。
  • 想用 $NF 但行内字段数不固定?NF 是字段总数,$NF 永远指向最后一个,安全。

4. 三剑客合体技(实战)

场景1:找出访问量TOP 5的IP

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

场景2:找出响应时间最慢的10个请求(假设最后一列是时间)

awk '$NF > 0 {print $NF, $0}' access.log | sort -nr | head -10

场景3:批量修改所有配置里的数据库连接串

grep -rl "db.example.com" /app/config/ | xargs sed -i 's/db.example.com/db.internal/g'

场景4:统计错误日志中各类错误码的数量

grep "ERROR" app.log | awk -F'ErrorCode=''{print $2}' | cut -d' ' -f1 | sort | uniq -c

场景5:从nginx日志里统计某个接口的平均响应时间

grep "/api/user/login" access.log | awk '{sum+=$NF} END {print sum/NR}'

场景6:实时监控日志,同时过滤和提取字段

tail -f app.log | awk '/ERROR/ {print $1, $NF}' | grep -v "health"

5. 一些大实话(坑与习惯)

grep

  • 想用 +、|、() 这类正则,**要么转义,要么用 -E**。我习惯直接 grep -E,省心。
  • 递归搜索时,默认会搜二进制文件,加 -I 跳过二进制,速度更快。
  • 用 --color=auto 高亮匹配,很多发行版默认开了,没开就自己加个alias。

sed

  • **永远先测试再 -i**:sed 's/old/new/g' file 看看输出对不对,没问题再 -i。
  • 跨平台脚本注意:Linux 的 sed 和 macOS 的 sed 在 -i 上行为不同,最好用 sed -i.bak 统一备份。
  • 正则里如果有 /,用其他分隔符(#、|)避免转义地狱。

awk

  • 如果只想打印某几列,但列数很多,可以用 $1=$1; print 来重新格式化(触发OFS)。
  • BEGIN 块里可以设置分隔符、打印表头;END 块里做汇总。
  • 大文件用 awk 完全没问题,它是流式处理,不会一次性加载整个文件。

6. 快速记忆法

想要干嘛
用谁
一句话口诀
找内容
grep
grep一把梭,-v反选,-C上下文
改内容
sed
sed替换,-i要命,先试再改
切列
awk
awk按列切,NF,统计用数组

这三样东西,别看命令行长,用熟了就是肌肉记忆。不用刻意背,用的时候回来翻翻,多踩几次坑,就刻脑子里了。能解决问题的,就是好家伙。

最新文章

随机文章