☰
Linux日志查看命令实战:tail/head/less/grep高效定位线上问题
2026/10/10 18:20:20 网站建设 项目流程

简介:Linux系统日志是诊断和调试问题的关键,这份PDF专为运维人员、开发者和初入门的IT从业者整理日志查看与分析的常用命令。内容系统覆盖tail/head实时监控与按行定位,cat/tac全文顺序及反向浏览,less/more分页翻看与关键字搜索,grep/sed正则过滤、上下文匹配和时间段截取,并给出wc统计行数的用法。针对实际场景,还梳理了排查错误关键字、定位指定时间窗口日志、查看关键字最后一次出现记录、统计关键字出现次数等典型操作,例如tail -f持续监控、grep -C查看上下文、sed配合grep筛选区间日志等。资源为单文件PDF,体积仅57KB,保存和移动都很方便;目前已有3140人学习下载。读者可快速建立从实时跟踪、分页查阅到正则提取、批量处理的日志分析思路,遇到线上故障时更从容地定位根因。

1. 查 log 日志先别急着 cat:先定范围再选命令

排查线上问题时,最磨人的不是找不到日志,而是日志文件太大、关键字太多、时间跨度太长,一条cat下去终端直接卡死,几百 MB 的文件把内存吃满。看 log 日志要学会的第一件事不是记命令,而是先回答三个问题:看哪一段、看哪些行、用什么工具打开。这份资源把 Linux 下查看日志的常用方法按tail/head、cat/tac、less/more、grep/sed分好类,正好覆盖这个问题。适合后端开发、运维和 QA 同学,尤其是那些经常要翻几个 GB 日志定位报错的人。先明确一点,所有命令都遵循同一个原则:能只读一部分,就不要读全文;能过滤,就不要全量扫描。

2. tail/head 与 cat/tac:先定「看哪一段」再动手

2.1 tail 的三种典型用法:实时跟踪、取尾部、指定起始行

日志文件的特点是新的内容永远追加在末尾,所以查看最新日志时,tail是出场率最高的命令,没有之一。它的三种用法覆盖了日常排查的绝大多数场景。

# 实时监控日志文件,文件有新内容自动刷出 tail -f app.log # 实时监控,同时限制只显示最后 10 行 tail -10f app.log # 查看文件末尾最后 100 行 tail -n 100 app.log # 从第 100 行开始显示直到文件末尾 tail -n +100 app.log

第一行的-f是 follow 的意思,终端会一直挂在那里,日志一有新行就滚动输出,我一般在排查接口报错时开两个窗口,一个盯tail -f,另一个用来触发请求。第二行-10f是简化写法,等价于tail -n 10 -f,作用不只是显示最后 10 行,而是从倒数第 10 行开始跟踪,适合日志刷得特别快、只想看最新一小段的时候用。

第三行tail -n 100是最常用的查看尾部方式,注意它等价于tail -n -100,这个负号在不同发行版上行为有差异,后面避坑章节会专门展开。第四行tail -n +100是很多新手容易搞混的点,这里的+100表示从第 100 行开始输出到文件结束,不是「倒数第 100 行」。如果日志文件有 5000 行,这条命令输出的是第 100 到第 5000 行,约 4900 行内容。

2.2 head 的边界:显示头部与「去掉头部」两种语义

head和tail恰好互补,一个从文件头开始,一个从文件尾开始。日常排查中它主要用来查看日志文件的起始部分,比如应用启动时的初始化信息、框架加载的配置项,这些内容通常只出现在文件开头。

# 查看文本开头的前 100 行 head -n 100 app.log # 查看除了最后 100 行之外的全部内容 head -n -100 app.log # 查看第 1 到第 50 行 head -n 50 app.log

第一行是最常规的读法,配合tail -n 100可以快速了解一份日志的首尾各自发生了什么。第二行head -n -100的语义要特别留意,它输出的是「去掉末尾 100 行后剩余的所有内容」,等价于sed -n '1,$-100p'的简化效果,适合比较文件主体和尾部新增内容是否有差异。第三行没什么特别,就是一个基础用法。

实际工作和tail组合起来,能解决一个很经典的问题:我只想看第 100 到第 120 行,怎么办?单独用head或tail都做不到,必须两个配合。

# 先 cat 带行号,取第 100 行之后的内容,再取前 20 行 cat -n app.log | tail -n +100 | head -n 20

这条管道命令的执行顺序是:cat -n给全文件加上行号,tail -n +100把第 100 行及之后的内容截出来,最后head -n 20只保留这段内容的前 20 行,最终得到的就是第 100 行到第 120 行。如果不要行号,去掉-n参数即可。注意管道里tail -n +100的+号不能丢,丢掉就成了取末尾 100 行,整个结果完全不对。

2.3 cat 和 tac:全文输出与倒序阅读的适用边界

cat和tac适合处理小文件,超过几十 MB 的日志文件不建议直接用它们全文加载,这是血泪经验。cat输出全文,tac从最后一行开始逐行逆序输出到第一行,相当于把整个文件倒过来看。

# 输出带行号的全文 cat -n app.log # 从尾部向头部倒序输出全部内容 tac app.log

tac在什么场景下有用?最典型的是查崩溃日志。很多应用在崩溃时会连续输出几十行的堆栈信息,其中最关键的错误描述往往在最后几行。先tac把文件倒序,grep一下关键字,第一条命中的内容就是崩溃输出的尾部,不用再翻几百行去找堆栈的起点。需要注意tac是整行反转,不是把每个字符倒序输出,所以日志时间戳从旧到新排列会变成从新到旧,查看时心里要有数。

2.4 组合命令的优先级:管道顺序决定结果

cat、head、tail组合时,管道的书写顺序决定了整个处理链路的方向。常见错误是把head和tail的位置写反,或者漏掉-n参数,导致输出的行数和预期完全不一样。

# 错误示范:想取 100-120 行,结果取到了最后 100 行的前 20 行 cat app.log | tail -n 100 | head -n 20 # 正确写法:先按起始行截断,再按数量取前 N 条 cat -n app.log | tail -n +100 | head -n 20

我一般建议在调试这类组合命令时,先用一个只有几百行的小测试文件跑一遍,确认输出行数符合预期再上生产日志。小文件用wc -l数一下总行数,心里先有个底,能避免在几 GB 日志上跑完才发现参数写错了。

3. less/more:大日志不炸内存的翻页与定位

3.1 为什么优先用 less 而不是 more

大日志文件面前,cat和more都靠不住。more只能向前翻页,按b键往回翻在某些终端实现上并不可靠;cat是一次性把全文读入终端,日志一上 GB 直接卡死。less的优势在于它并不会把整个文件加载进内存,而是按需读取当前屏幕需要显示的内容,打开一个 2 GB 的日志文件,内存占用可能只有几十 MB。

# 直接打开日志文件,进入翻页模式 less app.log # 设置退出时清除屏幕,避免日志残留 less -X app.log # 打开文件的同时定位到第 100 行 less +100g app.log

第二行的-X参数是我个人的偏好,不加的话退出less时日志内容会留在终端上,屏幕看起来全是残留文本,不方便接着敲下一条命令。第三行的+100g是「打开即定位到第 100 行」,这里的g是 goto 的意思,和进入交互界面后按100g跳转的效果一样。

more也提一下,它的价值在于极简环境里不一定装了less,但more基本是标配。more -10 app.log可以设定每页展示 10 行,适合看结构比较规整的配置类日志。除了这个参数,more在交互能力和搜索能力上都明显弱于less,所以只要环境允许,我一般直接用less。

3.2 打开即定位:行号、关键字、百分比、字节位四个入口

less最实用的能力不是翻页,而是「打开文件的那一刻就落在你关心的位置」。大日志文件动辄几十万行,打开后从第一行手动翻到目标位置不现实,四个定位入口正好覆盖常见需求。

# 定位到最后一行 less +GG app.log # 定位到第 100 个字节的位置 less +100P app.log # 定位到 50% 的位置 less +100p app.log # 搜索关键字,打开后直接定位到第一个匹配位置 less +/Exception app.log

+GG跳到最后一行,秒懂;+100P是跳到第 100 个字节,适合跳过文件头部的固定前方信息;+100p跳转到 50% 位置,注意这里的100p中的p是 percent,表示百分比,100 就是 100% 的位置,实际使用时写50p才是中间。第四个+/关键字是打开文件后立刻执行一次搜索,直接定位到第一个匹配「Exception」的行,这个在排查报错时比先打开文件再按/搜索少了一步操作。

进入交互界面后,常用的内部命令也别忘:按/关键字向下搜索,按?关键字向上搜索,搜索后用n跳到下一个匹配,用N跳到上一个匹配。翻页用Ctrl+F向后翻、Ctrl+B向前翻。退出直接按q。

3.3 大文件打开后卡顿的排查方向

如果less打开日志后翻页明显卡顿,多半不是命令本身的问题,而是文件的编码或格式有问题。二进制内容混入文本日志是一个常见原因,less会对每个字节做解析,遇到大量不可打印字符会拖慢渲染。解决办法是先退出,用grep -I确认文件里是否包含二进制内容,再决定是否要用strings清洗。

另外,日志文件如果是 Windows 行尾(CRLF),less的搜索和行号显示会略有偏差,常见做法是先用dos2unix转换再打开,或者用sed -i 's/\r$//'去掉回车符。这些细节不处理,搜索关键字时会出现明明看到有「ERROR」却grep不到的诡异情况。

4. grep/sed:把日志切成你想要的那一片

4.1 grep 的七个高频参数:从匹配到上下文控制

grep是日志排查的核心工具,但多数人只用过grep "关键字" file这一种形式。真正能提高效率的是下面这几个参数组合,它们分别解决「精确匹配」「只看匹配部分」「统计数量」「带行号输出」「保留上下文」这几类问题。

# 全字匹配,避免 ERROR 匹配到 ERROR_CODE grep -w "ERROR" app.log # 标记匹配颜色,auto 表示输出到终端时着色 grep --color=auto "Exception" app.log # 只输出匹配到的内容,而不是整行 grep -o -E "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" app.log # 统计文件中包含匹配字符串的行数 grep -c "timeout" app.log # 输出匹配行及其上下各 2 行内容 grep -n -C 2 "Exception" app.log

第一行-w是全字匹配,只匹配完整的单词,避免搜「ERROR」时把「ERROR_CODE」「ERROR_MSG」这种带后缀的也带出来,在日志里这种字段噪声特别多。第二行--color=auto让关键字在终端里标红,多文件日志刷屏时视觉定位快很多,always 模式会把颜色转义符写进重定向文件,所以重定向到文件时用--color=never更干净。

第三行-o配合-E是提取 IP 的经典写法,-o只输出匹配的子串而不是整行,-E启用扩展正则。第四行的-c统计的是匹配行的数量,不是匹配次数,一行里出现两次「timeout」也只算一行,这个区别后面统计章节会再强调。第五行-C 2是 context 的缩写,输出匹配行及前后各两行,排查异常时能直接看到报错发生前后发生了什么,比单独看那一行有用得多。

4.2 sed 按行号与时间范围切片的两种写法

sed是流编辑器,逐行读取、处理、输出。日志排查中它主要做两件事:按行号切片和按时间范围切片。行号切片适合日志文件没有统一时间格式,或者你想精确看某几行的场景。时间范围切片适合日志量巨大、只想看某几分钟内发生了什么的情况。

# 只打印文件第一行 sed -n '1p' app.log # 查看文件第 1 到第 10 行 sed -n '1,10p' app.log # 删除第一行后输出(不改原文件) sed '1d' app.log # 把日志中的 IP 地址替换为脱敏文本 sed 's/10\.0\.0\.[0-9]*/IP_HIDDEN/g' app.log # 查看 22:43 到 22:44 之间的日志记录 sed -n '/2025-03-18 22:43/,/2025-03-18 22:44/p' app.log

第一行的-n是关键,它关闭了 sed 的默认输出,配合p命令只打印匹配到的内容,不加-n的话每一行都会被打印一遍,输出会冗余一倍。第三行的1d是删除第一行后把剩余内容输出到屏幕,原文件不会变,想原地改要加-i参数,但我不建议在日志文件上直接-i,改坏了没法恢复。第五行是时间范围切片的写法,两个/正则/之间用逗号连接,p打印这个区间的内容。注意切片的截止条件是该正则第一次匹配到的时间戳,如果 22:44 这一分钟内有多条日志,从第一个 22:44 出现的位置开始就会停止输出,这个边界问题要在结果里人工确认。

4.3 组合场景一:按时间窗过滤并保留上下文

实际排查中,单个命令很少能直接解决问题,更多是grep和sed各出一招。比如先确认故障时间点,然后用sed切出那段时间的日志窗口,再对窗口内容做grep,同时带上上下文。

# 切出 14:00:00 到 14:05:00 的日志,过滤 Exception 并保留前后 5 行 sed -n '/2025-03-18 14:00:00/,/2025-03-18 14:05:00/p' app.log | grep -n -C 5 "Exception" --color=auto

这条管道的执行逻辑分成两段:前段sed把整个文件的时间范围压缩到 5 分钟内的日志切片,后段grep在这个切片里搜索关键字,-C 5把匹配行前后的 5 行一起输出,方便看异常发生时的完整上下文。-n给输出加上行号,这里的行号是整个文件的行号,不是切片内的相对行号,后续想用sed -n '行号p'回溯时可以直接用。

4.4 组合场景二:提取关键字前后内容与统计行数

有时候不关心整行内容,只想知道某关键字在日志里出现的频率,以及最后一次出现时的上下文。这两个需求可以分别用-c统计和-A控制行数来实现。

# 统计日志文件中包含 timeout 关键字的行数 grep -c "timeout" app.log # 等价写法,管道到 wc -l grep "timeout" app.log | wc -l # 查看关键字最后一次出现时的上下文:显示匹配行及后 10 行 grep "timeout" -A 10 app.log | tail -n 11 # 显示匹配行及前 10 行 grep "timeout" -B 10 app.log # 显示匹配行及前后各 10 行 grep "timeout" -C 10 app.log

第一行grep -c统计的是包含关键字的行数,第三行grep | wc -l先筛出所有匹配行再数换行符数量,两者在文件末尾没有换行符时会差 1,这个细节统计结果特别大时不太容易发现。第四行是「查看关键字最后一次出现」的经典组合:grep -A 10先取所有匹配行及之后 10 行,但输出会包含所有匹配位置,所以外面再套tail -n 11,取最后 11 行——也就是最后一次匹配的那一行加上它后面的 10 行。-B是向前的上下文,-C是双向的,实际使用中我更喜欢-C,因为报错前后的日志往往一样重要。

5. 避坑:这些日志命令的翻车现场与排查方法

5.1 tail -f 在日志轮转后失效

现象:用tail -f app.log实时跟踪日志,一段时间后终端不再输出新内容,但日志文件明明还在增长。

原因:日志文件被 logrotate 轮转,旧文件被重命名为app.log.1,新文件以app.log的名字创建。tail -f默认跟踪的是文件描述符,不是文件名,它还在读那个已经被重命名的旧文件,自然看不到新内容。

解决:改用tail -F,大写 F 会按照文件名重新打开文件,轮转后自动切换跟踪新生成的文件。这条命令在跟踪应用日志时基本可以无脑代替tail -f。

5.2 grep 把二进制文件当文本扫,刷屏且拖慢

现象:grep "ERROR" *.log之后终端刷出大量乱码,混杂着Binary file xxx.log matches的提示,命令执行时间也比预期长很多。

原因:日志文件里混入了二进制内容,可能来自应用异常写入的核心转储或编码错误的日志行。grep默认对二进制文件采取特殊处理,输出匹配提示而不是具体内容,但扫描过程仍然会完整读一遍文件,在超大文件上会拖慢速度。

解决:用grep -I忽略二进制文件,或者先用file app.log确认文件类型。对于确实混入二进制的日志,常见做法是先grep -a(以文本模式强制扫描)配合-o只提取匹配片段,避免整行乱码刷屏。

5.3 less +100p 与 less +100g 的语义混淆

现象:有人想用less +100p app.log定位到第 100 行,结果打开后停在了文件的 100% 位置,也就是最后一行,完全不是预期位置。

原因:100p中的p是 percent 的意思,表示定位到文件的某个百分比位置,100p就是 100%,即文件末尾。定位到第 100 行应该用+100g,g是 goto。

解决:用less +100g app.log准确跳到第 100 行。记忆口诀是p对应百分比、g对应行号。同理,+GG之所以定位到最后一行,是因为G在 vim 系操作习惯里代表文件末尾。

5.4 head -n -100 在不同系统上行为不一致

现象:在 Linux 上执行head -n -100 app.log输出的是「去掉最后 100 行之后的所有内容」,但在 macOS 或某些精简环境中执行同样的命令报错,提示非法参数。

原因:head -n -100这种负数参数表示「排除末尾 N 行」的语义是 GNU coreutils 的扩展,BSD 版本的head不支持这个语法。

解决:跨平台场景下改用兼容写法,sed -n '1,$-100p'或者grep -v配合行号处理。如果只是临时查看,最稳的还是head -n 100这种标准参数,负数参数的扩展功能只在确认系统支持时使用。

5.5 wc -l 统计的是换行符,最后一行会被漏掉

现象:用wc -l app.log统计日志行数,和日志系统里显示的行数总差 1 行,单独用tail -n 1又能看到内容。

原因:wc -l统计的是换行符的数量,不是真正的行数。如果文件最后一行没有换行符,wc -l不会把它计进去,日志系统按行读取则会把最后一段内容也算一行。

解决:统计行数时用grep -c ''或者awk 'END{print NR}'更准确。统计关键字命中行数时同理,grep -c是基于行的语义,而grep | wc -l是基于换行符的语义,最后一行没换行时两者差 1,这个差异在大批量统计对比时会导致误判。

6. 把日志查询做成日常习惯:一套可复用的快速定位流程

前面讲的是单个命令的用法和边界,这一章把它们串成一个固定的排查流程。我的习惯是:拿到一个线上问题,先不要急着去翻日志,先在终端执行一遍下面这个四步定位法,把范围缩小到一行或几行,再决定要不要用less进去细看。

# 第一步:确认故障时间窗口,通常来自监控告警或用户反馈 # 用 sed 切出该时间段的日志,输出到临时文件 sed -n '/2025-03-18 14:00:00/,/2025-03-18 14:05:00/p' app.log > /tmp/error_window.log # 第二步:在时间窗口内搜索关键字,带行号和上下文 grep -n -C 5 "Exception" /tmp/error_window.log --color=auto # 第三步:如果关键字太多,按频率排序,聚焦高发错误 grep -o -E "ErrorCode: [0-9]+" /tmp/error_window.log | sort | uniq -c | sort -rn # 第四步:针对最高频的错误码,提取它在整个日志中的全部出现位置 grep -w "ErrorCode: 503" app.log | wc -l

第一步切时间窗口,把分析对象从全量日志压缩到几分钟的小文件,后续所有操作都基于这个临时文件,速度大幅提升,也避免在原始文件上反复全量扫描。第二步定位关键报错,-C 5带出上下文,这一步基本能确定问题的直接原因。第三步做频率统计,-o -E提取结构化错误码,sort | uniq -c | sort -rn按出现次数降序排列,高频错误往往就是根因方向。第四步确认某个错误码的总量,判断它是个别偶发还是大面积发生。

这套流程里的每个命令都可以单独拆出来用在别的场景,比如sort | uniq -c | sort -rn也适合统计日志中出现最多的 IP。时间窗口的边界是这套流程最大的坑,sed的时间范围匹配是正则匹配,时间戳格式稍微不一致(比如日志里用2025-03-18T14:00:00而不是2025-03-18 14:00:00),匹配直接失效。我一般会先用grep "2025-03-18 14:00" app.log | head -1验证一下时间戳格式,再跑sed切片,这样能避免切出空文件还以为是日志没写。

从那以后我每次接到日志排查任务,都强制自己先跑一遍这个四步流程,哪怕问题可能很简单,也会先用它把范围框住,再决定是否深入。这套方法帮我避开了很多次直接在几个 GB 的日志里盲目grep的尴尬,也减少了对日志分析平台的依赖。希望这套流程能帮你更快地定位问题,把时间花在修复上而不是翻日志上。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询