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

资讯详情

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

Linux文本处理三剑客:grep、sed、gawk实战指南

Linux文本处理三剑客:grep、sed、gawk实战指南 简介这份PDF文档面向具备一定Linux基础、希望提升文本处理效率的技术人员系统梳理grep、sed、gawk三大命令行工具的使用方法。内容从grep的正则表达式元字符集、扩展集与POSIX字符类讲起结合命令选项与实例演示精准查找sed部分覆盖定址功能、调用格式、元字符集以及删除、替换、选定行范围、多点编辑、从文件读入等流编辑操作gawk部分则讲解执行方式、文件与字段处理、模式与动作、内部函数及控制结构展示结构化数据解析与统计汇总的灵活用法。资源包为1个PDF文件大小约342KB目录按工具分章、层级清晰便于按需检索。目前已有121人学习。读者可借助大量可直接套用的命令示例掌握日志分析、配置文件批量修改、CSV与日志数据统计等场景的实战思路并通过正则表达式的强化练习加深理解。1. grep、sed、gawk三条命令撑起 Linux 文本处理的日常日志排查、配置批量改写、数据清洗这三件事几乎占了 Linux 运维和开发日常的一半时间。很多人第一反应是写 Python 脚本但真到线上环境往往连解释器都不一定顺手反而是 grep、sed、gawk 这三条命令随取随用。grep 负责“找”sed 负责“改”gawk 负责“算和格式化”三者组合起来就是一套完整的文本流水线。这篇笔记面向的是需要处理日志、配置文件、CSV 导出的从业者从命令选项讲到正则表达式再落到能直接抄的实例。新手可以按步骤复现熟手可以重点看参数边界和踩坑记录。全文不堆概念每个命令都配可运行的代码块和参数说明。2. grep从日志里精准捞出你要的那几行2.1 grep 的匹配模式和三个必调选项grep 的核心行为是逐行匹配默认使用基本正则表达式BRE。它的选项很多但日常真正高频的只有三个-i忽略大小写、-n显示行号、-r递归目录。先看一个最小可运行示例从 Nginx 访问日志里找出所有 500 错误的行# -n 显示行号-i 忽略大小写500 是基本正则 grep -ni 500 /var/log/nginx/access.log # 递归搜索整个配置目录只列出匹配的文件名 grep -rl server_name /etc/nginx/ # 反向匹配排除包含 debug 的行 grep -v debug app.log逻辑说明-n让输出带行号方便后续用 sed 定位-r递归时默认会跟随符号链接如果目录里有循环链接需要加-R或--no-follow。参数说明-i在日志场景要慎用因为 HTTP 方法 GET 和 get 在日志里通常不会混用开了反而可能误匹配。-v是反向选择常用来过滤掉噪音行。真正拉开差距的是-E扩展正则和-PPerl 正则。-E让、?、|、()不用转义写起来干净很多# 用扩展正则匹配 4xx 或 5xx 状态码 grep -nE (4[0-9]{2}|5[0-9]{2}) access.log # -o 只输出匹配到的部分适合提取 IP grep -oE ([0-9]{1,3}\.){3}[0-9]{1,3} access.log | sort | uniq -c | sort -rn | head逻辑说明第一条用-E把分组和或运算写得更直观第二条用-o只保留匹配文本再配合sort | uniq -c做频次统计这是排查恶意 IP 的常见套路。参数说明-P支持\d、\b等 Perl 语法但并非所有发行版默认编译进去生产环境用之前先grep -P /dev/null测一下。2.2 用 grep 做上下文提取和文件筛选只看匹配行往往不够报错前后几行才是关键。-A、-B、-C分别控制后、前、上下文的行数# 显示匹配行及其后 3 行 grep -A 3 Exception app.log # 显示匹配行及其前后各 2 行 grep -C 2 timeout app.log # 结合 --include 只在 .conf 文件里搜 grep -rn --include*.conf listen /etc/逻辑说明-A/-B/-C在排查堆栈时特别有用因为异常信息通常跨多行。--include和--exclude用来限定文件范围避免在二进制文件或日志归档里浪费时间。参数说明-C等价于-A n -B n数字可以按需调整但不要设太大否则输出会淹没终端。一个容易被忽略的点是 grep 的退出码匹配到返回 0没匹配到返回 1出错返回 2。在 shell 脚本里用if grep -q ...判断时-q静默模式能避免输出干扰if grep -q ERROR app.log; then echo 发现错误触发告警 fi逻辑说明-q只返回状态码不输出内容适合条件判断。参数说明如果文件不存在grep 返回 2脚本里最好区分 1 和 2否则会把“文件缺失”误判为“没有错误”。3. sed流式编辑器的模式空间与保持空间3.1 sed 的工作模型一行一行读模式空间里改sed 是流编辑器默认逐行读取到模式空间pattern space执行脚本后再输出。它不会直接改原文件除非加-i。理解模式空间和保持空间hold space是用好 sed 的分水岭。先看最常用的替换# 把文件里的 old 替换成 new只替换每行第一处 sed s/old/new/ file.txt # 全局替换加 g sed s/old/new/g file.txt # 直接改原文件建议先备份 sed -i.bak s/old/new/g file.txt逻辑说明s是替换命令分隔符默认是/如果替换内容含/可以换成#或|。-i.bak会在修改前生成.bak备份这是血泪经验——线上直接-i改配置改错了没有后悔药。参数说明g只影响单行内的多次匹配跨行替换需要N或-z。sed 的地址定位决定了它改哪几行。地址可以是行号、正则、范围# 只替换第 5 行 sed 5s/old/new/ file.txt # 替换第 3 到第 8 行 sed 3,8s/old/new/g file.txt # 从匹配 start 的行到匹配 end 的行之间替换 sed /start/,/end/s/old/new/g file.txt # 删除空行 sed /^$/d file.txt逻辑说明地址和命令之间不加空格5s表示第 5 行执行替换。范围地址是“第一次匹配 start 到第一次匹配 end”如果 end 没出现会一直匹配到文件末尾。参数说明d是删除p是打印常配合-n只输出匹配行a是追加i是插入。3.2 保持空间sed 处理跨行数据的黑匣子模式空间是当前行的工作区保持空间是一块临时缓存。h把模式空间复制到保持空间H追加g反向复制G追加。用它可以实现倒序、合并行等操作# 用保持空间把文件行倒序输出 sed -n 1!G;h;$p file.txt # 把多行合并成一行用逗号分隔 sed :a;N;$!ba;s/\n/,/g file.txt逻辑说明第一条1!G表示第一行不追加保持空间h每行覆盖保存$p最后打印效果是倒序。第二条用标签:a和N把下一行读入模式空间$!ba表示不是最后一行就跳回a最后把换行替换成逗号。参数说明N会消耗下一行处理大文件时内存占用会上升几百 MB 的日志要谨慎。-i的跨平台差异是个经典坑。GNU sed 支持-i不带参数BSD/macOS 的 sed 要求-i 。写脚本时可以用变量判断或者统一用-i.bak规避# 兼容写法先备份再替换 sed -i.bak s/foo/bar/g file.txt rm -f file.txt.bak逻辑说明-i.bak在 GNU 和 BSD 上都能工作生成备份后手动删除既安全又兼容。参数说明如果确实不需要备份GNU 下用-iBSD 下用-i 不要混用。4. gawk把文本当表格来算和格式化4.1 gawk 的记录、字段和内置变量gawk 是 awk 的 GNU 实现核心模型是“记录record”和“字段field”。默认按行读记录按空白拆字段$1是第一列$0是整行。内置变量NR是当前行号NF是字段数FS是输入分隔符OFS是输出分隔符# 打印第一列和第三列 awk {print $1, $3} data.txt # 指定逗号为分隔符打印第二列 awk -F, {print $2} data.csv # 打印行号和字段数 awk {print NR, NF, $0} data.txt # 输出时用制表符分隔 awk -F, BEGIN{OFS\t} {print $1, $2} data.csv逻辑说明-F,等价于BEGIN{FS,}但写在命令行更简洁。BEGIN块在读取前执行适合初始化OFS。参数说明$NF是最后一个字段$(NF-1)是倒数第二个处理列数不固定的数据时很有用。gawk 的条件和循环让它能直接做统计# 统计访问日志里每个 IP 的出现次数 awk {count[$1]} END{for (ip in count) print count[ip], ip} access.log | sort -rn | head # 按状态码分组求和 awk {sum[$9]} END{for (code in sum) print code, sum[code]} access.log # 过滤出第 5 列大于 100 的行 awk $5 100 {print $0} data.txt逻辑说明count[$1]用第一列做数组下标END块在全部读完后遍历输出。$5 100是模式匹配条件为真才执行动作。参数说明gawk 的数组是关联数组遍历顺序不保证需要排序时管道接sort。4.2 gawk 的格式化输出和字符串函数gawk 的printf和 C 语言类似适合生成对齐的报表。字符串函数gsub、substr、split、match在清洗数据时很实用# 格式化输出左对齐 20 字符右对齐 10 字符 awk {printf %-20s %10s\n, $1, $2} data.txt # 把第一列的逗号替换成下划线 awk {gsub(/,/, _, $1); print $1} data.csv # 按冒号拆分第一列取第二部分 awk -F: {nsplit($1, arr, :); print arr[2]} data.txt # 截取子串从第 2 个字符开始取 5 个 awk {print substr($0, 2, 5)} data.txt逻辑说明printf的%-20s表示左对齐占 20 宽%10s右对齐占 10 宽。gsub直接修改字段内容返回替换次数。split把字符串拆成数组返回元素个数。参数说明substr的索引从 1 开始不是 0这点和很多语言不同。gawk 还支持if-else、while、for和自定义函数复杂逻辑不必硬塞进一行# 根据状态码分类输出 awk { if ($9 ~ /^2/) status 成功; else if ($9 ~ /^3/) status 重定向; else if ($9 ~ /^4/) status 客户端错误; else status 服务端错误; print status, $9 } access.log | sort | uniq -c逻辑说明~是正则匹配运算符/^2/表示以 2 开头。if-else链让分类逻辑清晰。参数说明gawk 的~和!~分别表示匹配和不匹配右侧可以是正则字面量或字符串变量。5. 避坑与排查三条命令最容易翻车的地方5.1 正则表达式在三种工具里的语法差异现象同一条正则grep 能匹配sed 报错gawk 结果不对。原因grep 默认 BREsed 默认 BREgawk 默认 ERE。、?、|、()在 BRE 里需要转义在 ERE 里不需要。解决统一用grep -E、sed -E、awk默认 ERE或者记住 BRE 的转义规则。写脚本时优先用-E可读性更好。5.2 sed -i 在 macOS 和 Linux 上行为不一致现象脚本在本地 macOS 跑得好到 Linux 服务器上sed -i报错或生成奇怪文件。原因BSD sed 的-i必须跟一个参数作为备份后缀GNU sed 的-i后缀可选。解决统一写sed -i.bak然后rm -f *.bak或者用perl -pi -e替代跨平台更一致。5.3 gawk 处理大文件时内存暴涨现象用awk {arr[$1]} END{...}统计几个 GB 的日志进程被 OOM kill。原因关联数组把所有 key 存在内存里key 数量大时内存线性增长。解决先用sort | uniq -c做外部排序统计或者用awk分片处理再合并结果。如果必须用 gawk考虑--profile观察内存或者换用mawk等更轻量的实现。5.4 grep 递归搜索时误入二进制文件和符号链接现象grep -r pattern /卡死或输出乱码。原因递归进入/proc、/sys或二进制文件匹配到大量无意义内容。解决加--include*.log限定文件类型加-I忽略二进制文件加--exclude-dir排除目录。生产环境搜索前先cd到目标目录不要从根目录开始。5.5 正则表达式中的贪婪匹配导致提取错误现象用grep -oE .*提取引号内容结果把整行都匹配了。原因*是贪婪匹配尽可能吃更多字符。解决用非贪婪写法但 grep 的 ERE 不支持非贪婪需要改用-P的.*?或者用[^]*限定字符集。gawk 里可以用match($0, /[^]*/)配合substr精确提取。6. 把三条命令串成流水线一个日志分析的完整实例单条命令再熟真正省时间的是把它们串起来。下面这个例子从 Nginx 访问日志里找出访问量最高的 10 个 IP并统计它们的状态码分布。先看完整命令# 第一步提取 IP 和状态码输出 IP 状态码 awk {print $1, $9} access.log /tmp/ip_status.txt # 第二步统计每个 IP 的总请求数取前 10 awk {count[$1]} END{for (ip in count) print count[ip], ip} /tmp/ip_status.txt \ | sort -rn | head -10 /tmp/top_ips.txt # 第三步对前 10 个 IP统计各自的状态码分布 while read -r cnt ip; do echo $ip (总请求 $cnt) grep ^$ip /tmp/ip_status.txt | awk {code[$2]} END{for (c in code) print c, code[c]} | sort done /tmp/top_ips.txt逻辑说明第一步用 gawk 把日志压成两列减少后续处理量第二步用关联数组计数并排序取头部第三步用while read逐行读取grep精确匹配 IP 后交给 gawk 做状态码分组。参数说明grep ^$ip 里的^和空格确保不会匹配到 IP 前缀相同的其他地址比如10.0.0.1和10.0.0.10。如果想进一步看每个 IP 的请求时间分布可以在第一步多取一列时间戳然后用 gawk 做分桶# 按小时统计请求量 awk -F[:[] {print $3} access.log | sort | uniq -c | sort -rn逻辑说明Nginx 日志的时间格式是[dd/Mon/yyyy:HH:MM:SS用-F[:[]把方括号和冒号都当分隔符$3就是小时。参数说明字段索引取决于日志格式先用head -1 access.log | awk -F[:[] {for(i1;iNF;i) print i, $i}确认每一列是什么。验证方法拿一份已知结果的日志手动数几行对比脚本输出。我一般会先在小样本上跑确认字段索引和正则没问题再放到全量日志上。另一个习惯是每个中间结果都落盘到/tmp出问题时能回看是哪一步偏了而不是从头再跑一遍。这套流水线的价值在于grep 做精确过滤sed 做格式清洗gawk 做聚合计算三者各司其职。真到线上排查往往不需要写完整脚本几条命令拼起来就能定位问题。希望帮到你。本文还有配套的精品资源点击获取
返回列表