尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Shell日志分析实战:高效排查故障的常用命令
平时排查服务器问题最常用的就是日志分析。不管是Nginx访问日志、业务应用日志还是系统日志很多故障的线索其实就藏在几十兆甚至几个G的log文件里。如果只会cat和vi翻日志遇到稍微大一点的文件就非常痛苦。我自己用了几年Shell从最早的只会tailgrep到后来慢慢把awk、sort、uniq、sed这些串起来用现在处理日志的效率高了很多。干脆把平时用得最多、出镜率最高的日志分析命令整理出来给经常跟日志打交道的后端、运维或者SRE同学做个参考也方便自己收藏备用。先明确一个前提下面的命令都是在Linux服务器上执行的Shell命令默认日志文件是文本格式。如果是Nginx、Apache访问日志或者Java、Go等应用打印出来的log基本思路都是通用的。如果你现在还在为一条条翻日志而头疼这份清单应该能帮你省下不少时间。1. 动手之前先搞懂日志格式和基础环境1.1 看懂日志里的字段分析才会快在敲命令之前强烈建议先花两分钟确认日志的格式。因为后面的awk、cut、sort都依赖列的位置。比如最常见的Nginx访问日志默认combined格式长这样192.168.1.10 - - [10/Feb/2025:13:55:36 0800] GET /api/user/123 HTTP/1.1 200 531 - Mozilla/5.0这一行里每个空格分隔的字段都有实际含义$1是客户端IP$2和$3是远程用户和认证用户一般用“-”占位$4是时间方括号$5是时区$6是请求方法$7是请求路径$8是协议$9是状态码$10是响应字节数。注意默认的awk以空格为分隔符$4会是“[10/Feb/2025:13:55:36”$5是“0800]”所以如果需要提取完整时间一般用sed或正则而不是awk按列提取。这个细节很多人第一次用会懵后面我会专门提醒。应用日志比如Java或Python框架的日志格式就更多了常见的有“2025-02-10 13:55:36.123 ERROR [http-nio-8080-exec-1] com.xxx.Service - 错误信息”。这时候如果想统计某个级别的日志条数直接grep关键字比awk按列更简单。所以我的建议是拿到日志先head -5看一眼弄清楚格式再下手这会省掉后面很多无谓的试错。1.2 查看日志的基础命令ls、tail、less登录服务器之后第一件事是确认日志位置和大小。我一般用ls -lh /var/log/nginx/access.log看文件大小避免用编辑器直接打开一个2GB的日志。less是比较适合大文件浏览的工具支持上下翻页、搜索/关键字按q退出。虽然less本身不直接用于“分析”但它是定位问题的好帮手。tail是用来查看文件末尾内容的tail -n 100 app.log看最后100行tail -f app.log进入实时跟踪模式。这两个命令是排查问题最常用的起手式。如果权限不够记得用sudo tail -n 100 /var/log/xxx.log。很多系统日志默认只有root或adm组能读普通用户打开会提示Permission denied。注意cat一个几百MB的日志会在终端刷出大量内容既看不清也浪费服务器资源正确做法是用tail或less。这一点算是我刚入门时踩过的最低级坑。2. 实时跟踪与关键字过滤tail、grep、管道组合拳2.1 tail -f 实时盯日志发布时的大救星说到实时日志tail -f的地位无可替代。比如线上某服务刚发布完你大概率想看到新日志有没有异常直接在另一个终端执行tail -f /var/log/app/app.log这时日志每增加一行终端就会立刻输出一行非常适合观察启动过程和接口调用。如果日志刷得太快眼睛根本看不过来可以配合grep只保留你关心的关键字tail -f /var/log/app/app.log | grep --line-buffered ERROR这里我特意加了--line-buffered原因是grep的输出在管道里默认是块缓冲的不一定会实时刷新加了它之后每次换行都能立刻打印做实时跟踪时非常重要。还有一个细节日志文件通常会被logrotate按天或按大小切分。如果使用tail -f文件被轮转后程序可能还盯着旧文件的句柄导致新日志根本显示不出来。这时候应该用tail -F大写F它会自动重新打开文件名对应的新文件。我每次发布时都习惯直接tail -F避免切日志后“假死”。2.2 grep 过滤日志灵活组合参数grep是最常用的文本搜索工具但很多人只会grep 关键字 file其实它有很多适合日志分析的参数-i忽略大小写搜索“error”时可以匹配“ERROR”。-n显示匹配行所在的行号方便回溯。--colorauto让匹配内容高亮一眼就看到命中位置。-E使用扩展正则比如grep -E ERROR|Exception app.log。-v反向匹配过滤掉不想看的内容比如grep -v healthcheck app.log。-A和-B显示匹配行的后几行和前几行。排查异常栈时grep -A20 Exception app.log能把完整堆栈打出来。-c统计匹配行数。比如grep -c ERROR app.log就能告诉你错误日志有多少行。举一个实际场景服务一直报超时但健康检查的请求也会打TIME_OUT日志干扰判断。我可以这样过滤grep -E TIME_OUT|TIMEOUT app.log | grep -v healthcheck先匹配所有超时再排除健康检查剩下的基本都是真实业务问题。这种“先用范围捞再用反向过滤去掉噪声”的思路在日志分析里非常常用。2.3 用管道把tail、grep、awk串起来单条命令能做的分析有限真正的威力来自管道。管道的核心逻辑是把前一个命令的输出作为后一个命令的输入一步接一步收敛信息。比如我想实时看最近访问某个接口的IP有哪些tail -F access.log | grep GET /api/order | awk {print $1} | sort | uniq -c这行命令里tail负责持续输出新日志grep筛出指定接口awk取IP列sort让相同IP聚在一起最后uniq -c统计每个IP来了几次。整个过程就像一条流水线每秒钟都在更新结果。初学者可能会疑惑为什么要先sort再uniq因为uniq只能合并“相邻且相同”的行如果IP乱序统计就全是1。这一点是uniq最大的特点也是一个超高频陷阱。我会在下一节专门演示。2.4 日志结果重定向把分析结果保存下来有时候分析结果需要保留或者发给同事这时候可以用重定向把终端的输出写入文件。比如把错误日志中所有包含“Timeout”的行连同上下文一起保存到本地grep -A5 -B5 Timeout app.log timeout_context.log如果是要把统计结果导出比如IP Top列表awk {print $1} access.log | sort | uniq -c | sort -rn | head -50 ip_top50.txt重定向命令本身很简单但有一个习惯值得养成一段复杂的日志分析命令先加上输出重定向就不会被终端刷屏搞到心态爆炸。后面再想二次分析直接对着文件操作比对着密密麻麻的终端输出舒服得多。3. 统计分析与排序sort、uniq、awk三剑客3.1 统计IP访问量一条经典命令的完整拆解如果说只能记住一条日志分析命令我会选这一条awk {print $1} access.log | sort | uniq -c | sort -rn | head -20这条命令的意思是从access.log中取出第1列客户端IP排序合并相同IP并统计次数再按次数从大到小排序最后取前20行。输出大概是1500 192.168.1.10 1200 203.0.113.5 980 198.51.100.2每一行前面的数字就是请求次数。这套组合基本是所有“Top N”统计的模板想统计请求次数Top N URLawk {print $7} access.log | sort | uniq -c | sort -rn | head -20想统计状态码分布awk {print $9} access.log | sort | uniq -c | sort -rn想统计浏览器UA的大类可以把整段UA做精确排序统计也可以先切割后统计。这里的第7列和第9列依然是Nginx默认格式的位置如果你用的日志格式不同先head一行确认列位置再改数字。3.2 状态码分布与5xx错误比例接口出问题的时候第一反应经常是看状态码有没有变多。用下面的命令可以快速看分布awk {print $9} access.log | sort | uniq -c | sort -rn输出可能长这样9800 200 300 304 87 404 25 502 12 500看到502和500有几十条就说明服务确实在处理出错或网关错误。如果再统计一下5xx错误占比可以用awk {print $9} access.log | grep -c ^5不过这样只能得到5xx的总条数想算占比还得结合总行数。我一般这样做total$(wc -l access.log) fives$(awk {print $9} access.log | grep -c ^5) echo $((fives * 100 / total))这里把两条命令的输出赋给变量再用整数运算算百分比。虽然Shell本身做不了太复杂的统计但随手算个比例完全够用。更复杂的分析我会直接导出到Excel或数据库那是另一个话题。想统计独立IP数量也就是去重后的IP个数可以用awk {print $1} access.log | sort -u | wc -lsort -u相当于sort后再做一次uniq直接输出唯一IP列表wc -l数行数。这个命令用来判断攻击来源规模、评估访问覆盖面都很好用。3.3 用awk算接口平均耗时和最大耗时如果业务日志里记录了接口耗时那么awk能派上大用场。假设日志每一行都是类似2025-02-10 13:00:01 INFO /api/order/query cost123ms我想统计这个接口的平均耗时和最大耗时可以这样grep /api/order/query app.log | grep -oE cost[0-9] | awk -F {sum$2; if($2max) max$2} END{print maxmax, avgsum/NR}这里大致逻辑是先用grep筛出接口和相关字段再用grep -oE提取“cost数字”的部分然后用awk以“”为分隔符取出数字边读边累加最后在END块里输出最大耗时和平均耗时。注意END块里的NR表示总共处理了多少行用它做分母就是平均值。实际工作中我还常用一个变形想把最慢的10个请求列出来直接grep /api/order/query app.log | grep -oE cost[0-9] | sort -t -k2 -rn | head -10这里sort -t -k2 -rn表示以“”为分隔符按第2列的数值倒序排序。很多人只会sort默认按字典序排结果出现“9 100”这种诡异现象所以遇到数字取最大值时一定要记得加-n按数值排序。4. 按时间窗口过滤与压缩日志处理4.1 用sed提取某个时间段内的日志有时候问题只在某个时间点出现比如今天10点到10点05分之间接口大量超时这时候不需要分析整天的日志只要切出这个时间窗口。最常见的做法是用sedsed -n /2025-02-10 10:00/,/2025-02-10 10:05/p app.log time_slice.log这条命令会把所有介于“2025-02-10 10:00”和“2025-02-10 10:05”之间的日志行打印出来并写入time_slice.log。要注意的是sed范围匹配是“看到起始行开始看到结束行停止”如果结束模式在当天只出现一次一般没问题但如果这个时间段内存在不完整匹配或者跨天就可能不准。跨天的情况我一般分开取sed -n /2025-02-09 23:55/,/2025-02-10 00:05/p app.log这就涉及两个日期的模式sed也能处理。除了sed用awk也能做时间过滤比如日志时间是固定前缀awk /^2025-02-10 10:0[0-5]/ app.log这个正则会匹配10:00到10:05的每一行。相较sedawk的过滤条件更灵活但对正则能力有一定要求。4.2 压缩日志也不怕zcat、zgrep、zless线上日志通常会按大小或日期轮转并且用gzip压缩比如access.log-20250210.gz。如果直接grep这些.gz文件会得到一堆二进制乱码这时候需要用到配套的z系列命令zcat file.gz在不解压的情况下输出解压后的内容相当于cat但不用解压。zgrep ERROR file.gz在压缩文件里直接grep。zless file.gz在压缩文件里分页查看。最常用的场景是“昨天某个接口报错了”我直接用zgrep GET /api/order access.log-20250209.gz | awk {print $1} | sort | uniq -c这样不需要解压就能拿到昨天的IP统计。如果需要分析连续几天的多个压缩文件也可以这样zcat access.log-2025020*.gz | grep ERROR | wc -lzcat会把多个文件的内容按顺序输出后面的命令再继续处理。这在实际排查历史问题时非常高效省去了“先解压再统计”的存储和时间开销。4.3 结合find定位多天前的历史日志日志文件通常都在同一个目录下用find可以快速定位符合条件的文件。比如查看一周前所有日志里出现了多少次“NullPointerException”find /var/log/app -name *.log.* -mtime 7 -exec zgrep -l NullPointerException {} \;这里-mtime 7表示文件的修改时间早于7天-exec对查到的每个文件执行zgrep-l让zgrep只输出包含关键字的文件名。如果文件数量很大可以把-l改成-c统计每个文件的命中行数。这套命令最大的价值是把“找哪个日志有问题”这件事自动化了。我遇到很多次线上告警第一反应是“这个问题之前是不是出现过”用findzgrep扫一遍历史日志往往能很快就找到类似的报错记录对根因分析特别有帮助。5. 实战案例一次接口响应慢的排查过程5.1 从反馈到第一条命令先确认现象有一次某项目反馈“订单查询接口很慢偶尔超时”我当时没有直接看监控而是先拿服务器日志来定位。第一步打开该接口对应的业务日志先看错误级别grep -E ERROR|WARN app.log | grep order/query | tail -50这里用tail -50是因为错误可能很多只需要最近50行就能看清楚当前状态。结果发现没有明显的异常栈只有几条连接池超时的WARN日志。于是判断问题可能是偶发性的需要按时间窗口进一步分析。5.2 用awk和sort找出最慢的请求既然不是每次必现我决定找出耗时最长的请求。项目日志里有类似cost123ms的字段于是我先过滤出这个接口的日志再提取耗时并排序grep order/query app.log | grep -oE cost[0-9] | awk -F {print $2} | sort -rn | head -10输出结果里排在前面的是4520 3100 2890 2500 ...明显有几条请求耗时超过3秒和用户说的“很慢”对得上。我后来又用sed取出这几条慢请求发生的时间点grep order/query app.log | grep -oE 2025-02-10 [0-9]{2}:[0-9]{2}:[0-9]{2} cost[0-9]把这些时间点记下来之后再把对应时间窗口的日志全部导出来看看同一时间系统里发生了什么。5.3 定位根因从日志走向结论通过时间窗口提取日志后我发现慢请求集中出现在上午10:00~10:02和下午14:30~14:32两个时间段而这两个时间段恰好有定时任务在批量处理数据。结合业务日志中的连接池等待信息最后判断是因为定时任务和在线接口抢数据库连接导致连接池不够用。改动方案是调整连接池上限和错开定时任务执行时间问题就不再出现。整个排查过程没有用复杂的监控工具全靠grep、awk、sed和sort就把问题锁定了。我举这个例子的目的是想说明Shell日志分析并不只是“敲几条命令”它是一种“从日志里快速提取信息并形成判断”的思维方式。命令只是工具思路才是核心。6. 速查表与避坑心得6.1 高频命令速查表为了方便收藏我把上面提到的常用命令整理成一张表后面用的时候可以直接对照。需求命令实时查看日志tail -F app.log实时只看指定关键字tail -F app.log | grep --line-buffered ERROR只看最后N行tail -n 100 app.log保留上下文搜索grep -B2 -A5 Exception app.log忽略大小写搜索grep -i error app.log统计关键字出现行数grep -c ERROR app.log统计IP Top 20awk {print $1} access.log | sort | uniq -c | sort -rn | head -20统计状态码分布awk {print $9} access.log | sort | uniq -c | sort -rn平均响应耗时grep 接口 app.log | grep -oE cost[0-9] | awk -F {sum$2} END{print sum/NR}按时间段提取日志sed -n /10:00/,/10:05/p app.log压缩日志搜索zgrep ERROR app.log.2.gz压缩日志统计分析zcat access.log.2.gz | awk {print $1} | sort | uniq -c统计总行数wc -l access.log这13条是我平时最常用的。可能刚接触Shell的同学觉得命令有点长其实你只要理解每一步在做什么整条命令就像一条流水线很容易记。6.2 容易踩的坑和实用小技巧最后分享几个我踩过比较多的坑建议收藏这条也一起收藏。tail -f 不等于 tail -F。线上日志按天轮转时用-f会盯住旧文件明明有新日志却看不到大写的-F会自动处理这种情况。现在我基本只用tail -F。uniq -c 前有空格。统计结果每一行开头会带空格比如“ 1500 192.168.1.10”如果要进一步处理可以用sed s/^ *//把开头空格去掉。grep -c 是按行数不是次数。如果一行里出现三次“ERROR”grep -c只统计这1行。要统计精确出现次数用grep -o ERROR file | wc -l。sort数字排序必须加-n。不加-n时100会排到20前面因为字符顺序是“1”“2”。只要做数值大小排序就加-n。日志时间要注意时区。很多日志的默认时间是UTC分析前先确认是不是北京时间不然你提取的时间窗口会整体偏移8小时这个坑非常隐蔽。大文件不要直接cat。终端输出大量内容既卡又看不清正确方式是tail、less、sed重定向到临时文件。管道输出加grep缓冲。实时跟踪时尽量带上--line-buffered参数否则你盯着屏幕看不到新日志还以为服务挂了。最后说说我自己的使用习惯我现在一般把IP统计、状态码统计、慢请求统计这几个常用管道写成几个shell函数放到.bashrc里一条命令就能出结果像这样function topip() { awk {print $1} $1 | sort | uniq -c | sort -rn | head ${2:-20}; } function topurl() { awk {print $7} $1 | sort | uniq -c | sort -rn | head ${2:-20}; }之后分析日志只需要topip access.log、topurl access.log就好。刚开始不用强迫自己全部记住先掌握tail、grep、awk三个基础命令再按需扩展sort、uniq、sed。用得多自然就熟了到时候你也会有自己的“常用命令收藏”。希望这份清单能帮你省下一些翻日志的时间。
RELATED

相关推荐

编程不用鼠标:键盘流效率体系与Vim模式实操指南

编程不用鼠标:键盘流效率体系与Vim模式实操指南

我是在一次线下技术交流会上遇到这位老哥的。聊到工作方式时,他随口说了一句:“我写代码十年,基本不用鼠标。”我当时下意识觉得这是在夸大,毕竟做现代 Web 开发,不上手拖拖拽拽,怎么可能。但后来我认真观察…

📅 2026/10/19 5:45:43
网络安全防御指南:从合规科普到DDoS与ARP防范

网络安全防御指南:从合规科普到DDoS与ARP防范

抱歉,我无法提供关于 DDoS、CC 攻击、ARP 欺骗等攻击手段的实战教程或命令大全。这类内容可能被用于未经授权的网络攻击,对他人财产和信息安全造成危害,同时也可能给使用者带来法律风险。如果你对网络安全领域感兴趣,我很乐意为你…

📅 2026/10/19 5:45:43
低空经济下车辆无人机协同配送路径优化:pymoo多目标求解实战

低空经济下车辆无人机协同配送路径优化:pymoo多目标求解实战

1. 项目概述与核心需求拆解说实话,这个标题一看就知道是运筹优化与物流工程方向的经典套路,但难得的是把“低空经济”这个政策风口和传统的车辆路径问题结合在了一起。车辆与无人机协同配送,本质上是在解决一个现实世界每天都在发生的问题&am…

📅 2026/10/19 5:45:43
MORE NEWS

更多资讯

📰

MATLAB随机森林分类器实战:从数据预处理到调参避坑

简介:基于随机森林的分类算法MATLAB简单实现,面向机器学习入门者与MATLAB开发者,定位于解决分类建模实践入门的一站式参考。资源包共8个文件,包含3个M脚本(分别承担随机森林训练与预测、ID3基础决策树算法及统计评估&a…

📰

Python量化投资避坑指南:数据清洗、回测与样本外验证实战

简介:Python股票量化投资课程配套课件包,面向希望用编程方式构建量化交易体系的初学与进阶学员,覆盖Python语法、数据分析、行情获取、技术指标、策略回测、自动交易与资金管理等模块。压缩包共收录142个文件,其中以85个Python源码…

📰

20+常用算法模型代码实现:分类、回归、聚类与集成工程手册

简介:这份模型算法大全面向数据分析、机器学习入门与进阶学习者,以及需要快速查阅经典算法实现的高校师生和算法工程师,系统整理了20余种常用算法模型及其代码实现,覆盖从统计建模到神经网络等典型场景,帮助读者在理论…

📰

diagram-design:复杂系统可视化设计规范,让架构图、流程图与时序图真正易懂

diagram-design 这个项目名字,听起来像是个画图工具,其实我把它做成了一整套“如何把复杂系统讲清楚”的设计规范。起因是我自己带团队时经常遇到一种尴尬:评审会上投出来的架构图非常漂亮,各种颜色、圆角、图标都齐全&#xff0c…

📰

内容创作遇信息缺失?三步补齐标题正文关键词与摘要

我注意到当前输入信息不完整。在制定写作方案之前,我需要先解决这个问题。当前输入存在的问题根据你的要求,正常的投稿格式应该包含四项关键内容:项目标题:当前仅有"rea"这一个词,无法判断具体指向项目正文&…

📰

R语言机器学习算法实现合集:从工程化结构到二次开发实战

简介:这份资源面向希望用R语言落地机器学习算法的数据分析初学者与进阶者,围绕监督学习与非监督学习两条主线,覆盖线性回归、逻辑回归、支持向量机、决策树、随机森林、梯度提升机、朴素贝叶斯、神经网络以及K-means聚类、关联规则等常见算法…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬