尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

sed 与 awk 实战:文本处理三剑客

sed 与 awk 实战:文本处理三剑客 sed 与 awk 实战文本处理三剑客 系列Shell 脚本系列第5篇 笔名厕所里的思想家—## 一、开篇引子在日常 Linux 运维和脚本开发中文本处理占到了日常工作量的 60% 以上。日志分析、配置修改、数据提取、格式转换——几乎每个任务都离不开对文本的操作。前面我们学了 Shell 脚本的基础语法、变量和流程控制但有没有遇到过这样的场景- 线上有个 200MB 的访问日志你想找出所有 500 错误的请求 IP 和访问时间- 一个配置文件里有 1000 行你需要批量修改其中某一类配置项- 从数据库导出的 CSV 文件你想筛选出某个字段满足条件的行再重新排序这些问题用标准 Shell 命令当然也能解决但用对工具效率是天壤之别。grep 是找sed 是改awk 是析。这三大工具组合起来几乎能处理任何文本任务。本篇不讲零碎语法直接上场景——每个场景都是你工作中大概率会遇到的问题跟着动手做一遍你就能掌握这三把利剑。—## 二、sed — 流编辑器批量修改文本### 2.1 sed 的核心哲学sed(Stream Editor) 的核心思想是逐行读取 → 匹配模式 → 执行操作。它不修改源文件除非加-i而是将处理结果输出到标准输出。基本语法bashsed [选项] 地址范围操作 文件### 2.2 场景 1批量替换 Nginx 配置中的域名nginx# 旧的 nginx.confserver_name old-domain.com;# 要把所有 old-domain.com 替换为 new-domain.com解法bashsed -i s/old-domain\.com/new-domain.com/g nginx.conf-i 是直接修改源文件s 是替换命令g 是全局替换每一行所有匹配位置不止第一处。**⚠️ 生产环境安全写法**bash# 先备份再修改sed -i.bak ‘s/old/new/g’ config.conf# 这样会生成 config.conf.bak 作为备份### 2.3 场景 2删除日志中的特定行假设你要清理 access.log 中的健康检查请求来自 k8s 的 /healthz 端点bash# 删除包含 /healthz 的行sed ‘//healthz/d’ access.log clean.logd是删除命令。多个模式可以用-ebashsed -e /\/healthz/d -e /\/metrics/d access.log clean.log### 2.4 场景 3只打印某个区间的行bash# 打印第 10 到第 20 行sed -n 10,20p file.log# -n 选项不自动打印只打印匹配的行# p 命令打印匹配的行### 2.5 场景 4在匹配行前后插入内容bash# 在包含 [server] 的行之前插入一行sed /\[server\]/i\# Server Configuration config.ini# 在包含 [server] 的行之后追加一行sed /\[server\]/a\timout 30 config.ini### 2.6 sed 的高级文本替换bash# 引用匹配内容反向引用echo helloworld | sed s/\([^]*\)\(.*\)/\2 \1/# 输出: world hello# 多模式替换sed -e s/ERROR/INFO/g -e s/WARN/INFO/g app.log# 只替换每行第二次出现的匹配sed s/,/|/2 data.csv # 每行第二个逗号换成 |** 核心口诀**s/旧/新/基础替换g全局替换-i直接写文件-n p只打印匹配行。---## 三、awk — 文本分析器结构化数据处理### 3.1 awk 的核心哲学awk的理念更接近数据库查询**把文本当表格行是记录列是字段**你可以按字段筛选、计算、格式化输出。基本语法bashawk [选项] BEGIN{前置命令} 条件 {行处理命令} END{后置命令} 文件每个字段用$1,$2, ... 引用$0代表整行。默认字段分隔符是空白空格/Tab。### 3.2 场景 5分析 access.log 统计各 IP 的访问量这是运维中最经典的需求bash# 假设日志格式IP - - [日期] 请求 状态码 大小# 192.168.1.1 - - [28/Jun/2026:10:00:00 0800] GET /api HTTP/1.1 200 1234awk {count[$1]} END {for (ip in count) print ip, count[ip]} access.log | sort -k2 -rn | head -10**分解**-{count[$1]}— 以第1列IP为键每出现一次计数1-END {…}— 文件处理完后执行-for…— 遍历字典输出 IP 和计数-sort -k2 -rn— 按第二列计数逆序排序-head -10— 取前 10### 3.3 场景 6筛选出 5xx 错误并格式化输出bashawk $9 ~ /^5[0-9][0-9]$/ {printf %-20s %-15s %s\n, $4, $1, $9} access.log输出[28/Jun/2026:10:00 192.168.1.1 500[28/Jun/2026:10:01 10.0.0.5 502**解释**-$9 ~ /^5…/— 第9列匹配 5xx 状态码-printf— 格式化输出%-20s左对齐占20字符### 3.4 场景 7CSV 文件数据提取与计算csv# employees.csvname,department,salary,years张三,技术部,15000,3李四,技术部,18000,5王五,市场部,12000,2赵六,市场部,14000,4**统计各部门平均工资**bashawk -F, NR1 {dept[$2]$3; count[$2]} END {for (d in dept) printf %s: %.2f (共%d人)\n, d, dept[d]/count[d], count[d]} employees.csv输出市场部: 13000.00 (共2人)技术部: 16500.00 (共2人)**关键点**--F,— 指定逗号为字段分隔符-NR1— 跳过标题行NR当前行号### 3.5 场景 8日志时间范围过滤bash# 筛选 10:00 到 10:59 之间的日志awk $4 ~ /^\[28\/Jun\/2026:10:/ access.log### 3.6 awk 内置变量速查| 变量 | 含义 ||:----|:----||NR| 已读取的记录数行号 ||NF| 当前行的字段数列数 ||$0| 整行内容 ||1..1..1..n| 第 1~n 个字段 ||FS| 字段分隔符默认空白 ||OFS| 输出字段分隔符默认空格 ||RS| 记录分隔符默认换行 |** 核心口诀**$1$2取字段{c[KaTeX parse error: Expected EOF, got } at position 5: 1]}̲ 做统计printf …(wc -l “$LOG_FILE”)echo “总请求数: $total”# 2. 状态码分布echo -e \n— 状态码分布 —“awk {codes[KaTeX parse error: Expected EOF, got } at position 5: 9]}̲ END {for (c in…LOG_FILE” | sort -k2 -rn# 3. 最活跃的前 10 个 IPecho -e “\n— 最活跃 IP Top 10 —“awk {ips[KaTeX parse error: Expected EOF, got } at position 5: 1]}̲ END {for (i in…LOG_FILE” | sort -rn | head -10 | awk {printf %-20s %d次\n”, $2, $1}‘# 4. 请求最多的 URL Top 10echo -e “\n— 最热 URL Top 10 —“awk {urlKaTeX parse error: Undefined control sequence: \? at position 10: 7; gsub(/\̲?̲.*/, , url); …LOG_FILE” | sort -rn | head -10 | awk {printf %-50s %d次\n”, $2,KaTeX parse error: Expected EOF, got } at position 2: 1}̲# 5. 4xx/5xx 错…(awk ‘9 /[45][0−9][0−9]9 ~ /^[45][0-9][0-9]9/[45][0−9][0−9]/’ “$LOG_FILE” | wc -l)echo -e \n— 错误分析 —echo 4xx/5xx 错误数: $errorsecho 错误率: $(echo “scale2; $errors * 100 /total∣bc)total | bc)%### 5.2 场景 12配置文件中批量修改参数bash#!/bin/bash# update_config.sh — 批量修改配置文件CONFIG/etc/myapp/config.ini# sed 批量修改sed -i.bak \ -e s/^debugfalse/debugtrue/ \ -e s/^port8080/port9090/ \ -e /^#.*database_url/s/^#// \ total∣bc)CONFIG”# awk 校验修改结果echo 修改后的关键配置 “awk -F ‘/^(debug|port|database_url)/’ “$CONFIG”### 5.3 场景 13多文件数据合并与分析bash# 合并多个服务器上的日志统计按小时的请求分布cat server1.log server2.log server3.log | \ awk ‘{split($4, arr, /[/:]/); hourarr[5]} {hourly[hour]} END {for (h in hourly) printf “%02d:00 → %d次\n”, h, hourly[h]}’ | \ sort### 5.4 场景 14实时监控与报警bash#!/bin/bash# monitor_5xx.sh — 实时监控 5xx 错误并报警tail -f /var/log/nginx/access.log | \ awk ‘9 /5[0−9][0−9]9 ~ /^5[0-9][0-9]9/5[0−9][0−9]/ { system(echo “[ALERT] 5xx错误: $0 “” | mail -s “告警: Nginx 5xx错误” adminexample.com”) printf “ [%s] 5xx错误: %s %s\n”, $4, $1, $9 }’—## 六、性能与效率对比| 场景 | sed | awk | grep | 推荐 ||:----|:—:—:—:----:|| 简单替换 | ⭐⭐⭐ | ⭐⭐ | — |sed|| 删除特定行 | ⭐⭐⭐ | ⭐⭐ | — |sed|| 统计聚合 | — | ⭐⭐⭐ | — |awk|| 字段筛选 | — | ⭐⭐⭐ | — |awk|| 正则搜索 | ⭐⭐ | ⭐⭐ | ⭐⭐⭐ |grep|| 上下文显示 | ⭐ | — | ⭐⭐⭐ |grep -C|| 复杂数据管道 | ⭐ | ⭐⭐⭐ | ⭐ |awk pipe|| 处理大文件(1GB) | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |sed/grep|经验之谈能用 grep 解决的问题不要用 sed能用 sed 解决的不要用 awk。工具越专用效率越高。但当任务复杂到需要算的时候awk 是最趁手的。—## 七、常见的坑与避坑指南### 7.1 sed 中的正则转义bash# ❌ 错误特殊字符未转义sed ‘s/old.com/new.com/g’ file # . 会匹配任意字符# ✅ 正确转义点号sed ‘s/old.com/new.com/g’ file# 或者用扩展正则 (-E)sed -E ‘s/old.com/new.com/g’ file### 7.2 awk 中的 shell 变量传递bash# ❌ 错误shell 变量直接在 awk 中使用keyword“ERRORawk ‘0 /0 ~ /0/keyword/’ log # awk 不识别KaTeX parse error: Expected EOF, got # at position 8: keyword#̲ ✅ 正确使用 -v 传递变…keyword” ‘$0 ~ kw/’ log# 或者用单引号跳转awk 0 /′0 ~ /0/′keyword”’/’ log### 7.3 大文件处理bash# 处理超大文件时用管道避免中间文件# ❌ 差先 grep 写入中间文件grep “ERROR” huge.log errors.logawk ‘{count[$1]} END {for …}’ errors.log# ✅ 好管道直接传递grep “ERROR” huge.log | awk ‘{count[$1]} END {for …}’—## 八、总结| 工具 | 说人话 | 最擅长 ||:----|:------|:-------||grep| 文本搜索器 | 在文件堆里找东西 ||sed| 文本手术刀 | 批量替换、增删行 ||awk| 文本数据库 | 按列分析、统计、格式化 |这三把剑组合起来你在 Linux 下的文本处理能力就基本毕业了。下次遇到任何文本处理任务先问自己三个问题1. 要找人→grep2. 要改东西→sed 3. 要算数据→awk—下一篇预告Shell 调试技巧——告别脚本报错找不到原因
返回列表