监控dmesg匹配首条目标日志时sed/grep未及时触发问题
问题根因
阻塞问题和sed、grep的匹配逻辑无关,核心是管道场景下的默认块缓冲机制导致的:
dmesg -w是持续监听内核环形缓冲区的实时输出模式,当它的输出目标不是交互式终端(也就是通过管道传给sed/grep时),会默认启用大小通常为4KB的块缓冲——不会每生成一行日志就立刻写入管道,而是攒满整块缓冲区才会一次性把数据发给下游命令。- 你观察到的「第二条匹配日志才触发后续逻辑」是典型的缓冲未刷新表现:第一条包含
protocol的日志生成后,数据一直滞留在dmesg的输出缓冲区里,sed/grep根本读不到这行内容;直到下一条任意日志写入,把缓冲区凑满触发刷新,下游命令才收到匹配内容、执行退出。如果第一条匹配日志之后一直没有新的内核日志输出,脚本就会永久阻塞。 - 原脚本还有三个额外问题:一是两处
eval完全没有必要,属于冗余写法还存在命令注入风险;二是下游sed/grep退出后,上游的dmesg -w进程不会立刻自动退出,会残留僵尸进程占用资源;三是sleep 1写在while判断位会导致脚本启动后先空等1秒才开始监听,存在日志漏报窗口。
修复方案
用stdbuf强制dmesg启用行缓冲,让每一行日志生成后立刻写入管道,同时给下游grep/sed也开启行缓冲避免二次阻塞,清理冗余逻辑和残留进程,修正后代码如下:
#!/bin/bash # 提前一次性创建归档目录,无需每次循环重复执行 mkdir -p /home/user/dmesg/ while true; do # 强制dmesg行缓冲输出,grep匹配到第一行目标内容就立刻退出 stdbuf -oL dmesg -w | grep -m 1 -q --line-buffered 'protocol' # 清理可能残留的dmesg监听进程,避免僵尸进程 pkill -P $$ dmesg 2>/dev/null # 归档当前dmesg日志,文件名冒号替换为下划线,兼容各类文件系统 dmesg -T > "/home/user/dmesg/dmesg-$(date +%d_%m_%Y-%H_%M).log" # 清空dmesg环形缓冲区 dmesg -c >/dev/null # 强制终止目标进程 pkill -x -9 programm # 完成一轮处理后等待1秒再开启下一轮监听,避免重复触发 sleep 1 done
补充说明
- 如果偏好sed实现匹配退出的逻辑,把管道行替换为以下写法即可,
sed -u参数用于强制sed无缓冲:stdbuf -oL dmesg -w | sed -u '/protocol/Q' - 不建议在文件名中使用
:字符,该字符在FAT/ExFAT等文件系统、部分备份工具、跨平台同步场景下会被判定为非法字符,替换为下划线通用性更强。
内容的提问来源于stack exchange,提问作者tilch
相关产品推荐
相关产品推荐

