awk、tail、grep、sed四件套:高效排查日志的实战指南

发布时间:2026/9/30 3:16:14
awk、tail、grep、sed四件套:高效排查日志的实战指南 同事捧着终端一屏一屏翻日志文件翻到接口报错还要先找半天行号再用鼠标慢慢选。我站在旁边看了一会儿实在没忍住现场给他演示了一套 awk、tail、grep、sed 组合拳。十分钟后他从“打开文件慢慢看”变成了“一条管道命令直接定位到具体错误”。这篇就把当天教他的完整思路和命令写出来适合所有还在用编辑器翻日志、被大日志文件卡到怀疑人生的开发、运维和测试同学。1. 为什么查日志慢思维惯性比工具更耽误事1.1 大部分同事查日志的问题出在哪先说最常见的场景线上服务报错了同事第一步是找到日志文件然后双击用文本编辑器打开。文件稍微大一点比如 200MB 的 nginx 日志编辑器直接卡死鼠标转圈整个人也转圈。这还算好的有些人习惯打开文件之后用搜索框搜 “ERROR” 或 “Exception”搜出来几十条再一条条往下翻翻的过程中还得自己记住上下文经常翻到一半忘了前面那条异常是什么。这种做法的核心问题不是“不努力”而是把日志当成了一份静态文档而不是一条持续流动的文本流。查日志的本质是过滤与定位先缩小范围再提取关键字段最后统计出问题趋势。用编辑器做的每一步都是全量加载哪怕你只需要看最后 50 行它也先把整个文件读一遍所以慢是必然的。我第一次意识到这个问题是看到一个同事用less打开日志后按G跳到最后一行再往上翻屏翻了一百多页。他明明只想知道“刚才那次请求为什么 500”却花了二十分钟在翻屏。从那时起我就觉得查日志的效率问题必须从操作习惯上解决而不是靠肉眼硬扛。1.2 为什么这套组合拳是刚需awk、grep、sed、tail 这四个命令任何一个 Linux 环境几乎都自带不需要装额外的日志平台不需要给服务器配 Kibana也不用把日志导到本地再用 Excel 筛选。它们单个拿出来都很简单但配合管道符号组合起来就能做到一次定位、一次统计。这背后的核心思想是管道把前一个命令的输出交给下一个命令处理。日志经过 grep 过滤、sed 截段、awk 提取字段、sort 和 uniq 做排序统计最终输出的就是你要的答案而不是一整堆需要人肉再加工的数据。组合起来后整个排查过程可以压缩成一条命令十几秒内完成。图形化日志工具当然好但现实是很多服务器出于安全和管理限制你不能随意装 Agent日志平台也不是每个团队都有。这时候命令行组合拳就是最低门槛、最高通用性的解决方案。哪怕是临时登录一台陌生机器只要 Shell 能用这套方法就成立。2. 四个命令的角色分工与核心用法2.1 grep先学会精准过滤grep 的地位不用多说它的核心功能是“按行过滤”。但要过滤得精准有几个点值得花时间练。最基本的用法是grep ERROR app.log输出所有包含 ERROR 的行。问题在于日志里经常一个请求会打十几行甚至几十行日志你只过滤 ERROR 会丢掉异常发生前的上下文。所以grep -B 5额外打印匹配行之前的 5 行grep -A 5打印之后的 5 行grep -C 3是前后各 3 行这个组合我几乎每次排查都在用。正则表达式是另一个分水岭。默认的 grep 虽然也能用部分正则但推荐直接养成用grep -E的习惯。比如你要同时过滤多种级别或者多个关键字grep -E ERROR|WARN|NullPointer比写多条 grep 再合并高效得多。如果只有一组特征也可以用grep -E 2025-01-15 14:[0-9]{2}.*timeout这种写法把时间范围和关键词一次性匹配掉。还有个容易被忽略的细节是grep -c和grep -n。grep -c只输出匹配次数适合先确认问题大约占多少行不至于一上来就喷出几百条把屏幕刷爆grep -n输出行号配合sed -n 行号p去精确取某一行效果拔群。至于grep -v反向过滤典型场景是你不想看 DEBUG 和 INFO直接grep -vE INFO|DEBUG把干扰项一次性去掉。2.2 sed范围截取与原地处理很多人对 sed 的印象是“替换命令”实际上查日志时它最重要的能力是按范围截取内容。sed -n 10,20p app.log打印第 10 到 20 行-n表示“不打印默认输出”p表示“打印匹配范围”。在日志排查里更常用的是按模式范围截取sed -n /2025-01-15 14:00/,/2025-01-15 15:00/p app.log它会把第一行匹配到 14:00 的内容开始打印一直到匹配到 15:00 的那一行结束。这种按时间范围截取是查“某段时间内发生了什么”的神器。还有一个用途是删除无关行。sed -i /healthcheck/d app.log可以原地删除所有健康检查的日志但我不建议你直接加-i因为一旦删错无法恢复。安全写法是先生成到新文件sed /healthcheck/d app.log app_clean.log确认无误后再处理。同样的逻辑适用于替换sed -i.bak s/old_text/new_text/g app.log-i.bak会先生成 .bak 备份再替换这是我在生产环境唯一敢用的加-i的方式。注意sed的范围正则建议精确到分钟级别不要只写14:就完事。之前我就因为范围首尾不够精确把整段从 14 点到次日凌晨的内容全打印出来了差点造成误导。2.3 awk字段提取与统计如果只用一个命令做字段提取和统计那必须是 awk。它的核心逻辑是“按行读取、按分隔符切列、逐行处理”。常见日志格式一般是空格分隔比如2025-01-15 14:23:45 ERROR OrderServiceImpl - payment failed。用awk {print $1, $2, $3, $NF} app.log$1是日期$2是时间$3是级别$NF是最后一个字段。这里$NF是个好东西不知道一行有几个字段时用它直接取最后一个。如果日志是逗号或者竖线分隔的就得指定-F分隔符。比如 CSV 风格的访问日志awk -F , {print $1, $5} access.log。很多同事在这里犯的第一个错误就是不指定分隔符直接{print $5}结果发现输出跟想象完全不一样。正确做法是先看日志样例确定分隔符再决定怎么写。awk 的统计能力在排查时尤其有用。统计某段时间内 ERROR 出现次数awk /ERROR/{count} END{print count} app.log。按接口聚合耗时先 awk 切出接口字段和耗时字段再用sort | uniq -c | sort -rn排序秒出最慢的几个接口排名。如果日志里是 JSON 格式awk 也能处理只是需要配合-F 来切字段稍微绕一点但完全可行。2.4 tail实时跟踪与文件尾读tail 在排查“正在发生”的问题时是无可替代的。tail -f app.log持续输出新追加的内容适合发布上线时或者复现故障时盯着看。但直接 tail 的问题在于日志流量一大输出的信息会非常多你根本来不及看完。这时候必须配合管道过滤tail -f app.log | grep ERROR实时输出所有新产生的 ERROR。你还可以用tail -n 100只看最后 100 行。这个看似基础但配合场景用起来很顺手比如刚才发生了一次报错tail -n 200 app.log | grep -A 10 NullPointerException可以直接抓到最近 200 行里的完整异常堆栈不用再翻整个文件。实际使用中有一个隐藏坑tail -f app.log | grep ERROR的时候如果 grep 输出没有及时刷新很可能是因为管道的缓冲机制而不是命令本身有问题。解决办法是给 grep 加--line-buffered强制行缓冲让每一行匹配结果都立刻打出来。如果要在实时流里顺带统计也可以管道到 awk但要注意 awk 默认也有缓冲同样可以用fflush()或者system()强制刷新不过日常排查还是建议“先过滤、再统计”不要一条命令吃太胖。3. 现场实战从出问题到定位的三步组合拳3.1 第一步先用 tail grep 缩小时间窗当天同事的问题是“下午支付接口报错具体不知道从什么时候开始的”。我让他先把范围缩小到最近几分钟。第一步命令是grep -c ERROR app.log先看全文件 ERROR 总量结果输出有几千条显然不能直接扑上去。继续看最近两分钟新增了多少tail -n 200 app.log | grep -c ERROR这条命令的作用是只看最后 200 行统计其中的 ERROR 数量。如果结果是 0说明报错可能已经停了直接看更早的段落如果数量不少说明异常还在持续接着往下查实时日志tail -f app.log | grep --line-buffered ERROR | tail -n 20这里要解释一下管道顺序tail -f持续输出全部日志grep过滤出 ERRORtail -n 20只保留最近 20 条匹配结果。因为前两步已经把流量控制住了输出不会刷屏可以安心定位时间点。看到错误集中在15:47出现于是我们把时间窗锁死在 15:45 到 15:50。这一步的关键是“先看总量再拉窗口”。很多新人一上来就grep ERROR app.log几千行直接糊一脸心态瞬间崩了。先grep -c计数再决定用 tail 还是 sed 截段节奏会舒服很多。3.2 第二步用 sed 抽取指定时间段的日志确定时间窗后用 sed 把这段时间的完整日志全部导出来保存成一个临时文件后面所有分析都在这个文件上做不用反复打开几百兆的原文件。sed -n /2025-01-15 15:45/,/2025-01-15 15:50/p app.log /tmp/error_window.log这里有个非常重要的注意事项sed的两个正则必须都能在日志里匹配到行而且首尾顺序不能反。如果 15:45 这个时间点恰好没有日志输出sed会一直打印到文件末尾结果范围完全错乱。所以我通常先跑一条命令确认边界存在grep -E 2025-01-15 15:45|2025-01-15 15:50 app.log | head -2看到两个时间点都有日志行再执行 sed 截段。另外提醒一下有些日志的时间格式是15:45:01.123而有的只有15:45:01。如果你截取的正则写得太粗会把 15:45 到 15:50 之间所有分钟都包含进去这通常没问题但如果想精确到秒就必须把正则写成15:45:0[0-9]这种形式。临时文件生成后在这个文件上继续操作就安全多了。后续的 grep 和 awk 都只处理 5 分钟内的日志匹配速度和应用效果都提升一个量级。这个“先截段、再分析”的习惯是我认为 sed 在日志排查里最值钱的一招。3.3 第三步用 awk 精确切割字段并统计临时文件里有几百行 ERROR 日志但光看几百行文本还是低效。我让同事先看看日志长什么样再决定怎么切字段head -3 /tmp/error_window.log日志格式大致是2025-01-15 15:45:11 ERROR OrderService - createOrder#1234 response: 500 time2300ms 2025-01-15 15:46:02 ERROR OrderService - createOrder#1235 response: 500 time4100ms 2025-01-15 15:47:31 ERROR PaymentService - pay#8866 response: timeout time12001ms我让他先用 awk 把时间、服务和耗时都切出来awk {print $2, $3, $4, $NF} /tmp/error_window.log这里$2是时间$3是级别$4是服务名$NF是最后一个字段耗时。输出变成整齐的四列比看原始堆栈清爽多了。接着做聚合统计按“服务名”分组统计每个服务各出现多少次 ERRPR。因为服务名在$4但这一列后面可能还有别的字段所以先确认字段编号再分组awk {print $4} /tmp/error_window.log | sort | uniq -c | sort -rn输出结果一目了然PaymentService 出现 32 次OrderService 出现 18 次。然后针对最严重的 PaymentService 再拉完整堆栈grep -A 20 PaymentService /tmp/error_window.log | head -80这下问题精确到了具体服务的某几行异常堆栈上。整个过程大约一分钟同事在旁边看完直接愣住说“原来查日志可以这么查”。4. 日常排查中的隐藏技巧与常见坑4.1 常见问题速查与解决我把自己踩过和见过的一些坑整理成一张速查表方便你遇到类似情况时直接对照处理。现象原因解决办法编辑器打开大日志卡死工具一次性加载全文件改用less或直接管道处理先wc -l看行数tail -f app.log | grep ERROR没输出grep 输出缓冲导致给 grep 加--line-bufferedawk {print $5}输出为空或错位分隔符不是空格或字段编号不对先head -1看原始格式再用-F指定,或|sed按时间截取范围错乱首尾边界正则匹配不到或匹配过多先 grep 确认时间边界存在正则写精确到分钟日志中文或特殊字符乱码文件是 UTF-8但终端编码不对用file app.log查询编码终端改为 UTF-8grep 匹配不到某些关键字日志里大小写混合或包含特殊符号用grep -iE忽略大小写或用转义符处理特殊符号同一日志反复搜索效率低每次都全量扫描大文件先用 grep/sed 截出临时文件再二次分析还有一个很隐蔽的问题是tail -f管道后面的命令遇到文件轮转logrotate时偶尔会停住不输出。这时候用tail -F大写来替代tail -f它能处理文件名被改名重建的情况更适合跟踪持续写入的滚动日志。4.2 一些独家的实操心得先说一个我在现场教学时反复强调的习惯拿到日志后不要急着写命令先花十秒钟看字段结构。日志格式决定了你要用空格切、逗号切还是先 grep 再 awk。格式都没看清就写命令后面所有结果都可能是错的到头来还得回来重看原始数据更浪费时间。再说一个更实际的经验一条组合命令不要一口气写太长。我见过有些同事把 grep、sed、awk、sort、uniq、head 全串在一行一旦中间的管道输出不符合预期根本没法排查哪一步出了问题。我的习惯是先逐步执行比如grep -E ERROR|timeout app.log | head -20看看匹配结果合理再往后面接awk {print $4} | sort | uniq -c。每加一段管道就检查一次输出确认无误再继续最终把命令稳定下来后再把它写成一个 shell 函数或者别名保存。接脚本化这一点教你一个很实用的技巧在你经常排查的服务上把常用命令写成函数放进~/.bashrc。比如logerr() { grep -E ERROR|Exception|timeout $1 | tail -n ${2:-50} }以后调用logerr app.log 200就能直接看到最近 200 条异常。这个函数我教过好几个同事普遍反馈“查日志终于不用再翻半天了”。如果团队里大家用得顺手还可以把固定环境的日志路径也封装进去排查速度会再上一个台阶。生产环境操作我最后再强调一遍sed -i这类原地改动命令能不用就不用真需要改文件时先备份、先备份、先备份。重要的事情说三遍一次误操作可能把关键日志截掉一大段连找回的办法都没有。教完同事那套组合拳之后第二天他专门跑过来跟我说排查支付接口报错从原来二十分钟起到现在两三分钟就能拿到异常栈和频率统计整个人都轻松了。我在实际使用中最大的体会是查日志这件事真正的门槛不是记命令而是建立一种“文本流思维”——把日志当作可过滤、可截取、可统计的流水而不是一份需要肉眼翻阅的文档。当你习惯了这种思维方式awk、tail、grep、sed 就不是四个孤立命令而是一整套处理信息的工具箱。遇到再大的日志文件心里也只有一句“先过滤、再截段、后统计”自然不会慌也更加从容。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询