当前位置:首页>Linux>嵌入式Linux调试心法:用grep、sed、awk驾驭文本流

嵌入式Linux调试心法:用grep、sed、awk驾驭文本流

  • 2026-10-11 07:31:41
嵌入式Linux调试心法:用grep、sed、awk驾驭文本流

大家好,我是情报小哥~

前几天跟一个嵌入式linux软件前辈,他跟我分享了一句话: "在资源匮乏的嵌入式世界里,最锋利的工具往往早已躺在 /bin 目录下。",这是踩了多少坑才有这么痛的领悟~

大家想象一下这样的场景,当你蹲在调试台前,盯着串口终端里疯狂滚动的日志,根本刹不住车。可能是驱动初始化失败,可能是某个进程反复被 OOM Killer 干掉,但你没办法装一个带高亮的日志分析器——这个板子只有 64MB 内存,跑着裁剪过的 BusyBox,连 less 都是简化版。

你现在急需把网络接口的 IP 改掉,可板子上没有 vim,甚至没有 nano。你总不能为了改一行配置,就把文件系统重新打包烧录一次吧。

这些场景,几乎每一位嵌入式工程师都经历过。我们习惯了资源的限制,也因此比任何人都更懂得克制地使用工具。今天想和你聊的,正是嵌入式调试中最克制、也最锋利的三件武器:grep、sed、awk。

不只是命令,是一种哲学

Unix 世界有句老话:一切皆文件。日志是文件,配置是文件,进程信息是文件,就连 /proc 里的内存、中断、CPU 状态也都是文件。一旦接受了这个设定,你会发现调试问题的核心,就变成了在文件构成的文本流里寻找线索、裁剪信息、提取结论。

更重要的法则是:小工具通过管道组合。grep 负责过滤,sed 负责修改,awk 负责统计和格式化。它们每一个都只做一件小事,但用 | 串起来,就能在几秒钟内完成你原本想写一个 Python 脚本去搞定的事情。

这恰恰是嵌入式系统设计的精髓——做减法。不引入新的依赖,不动用编译器,就地取材,用系统已有的能力把问题解决掉。当你习惯了“组合而非重写”,你会发现自己的设计思路也开始变得清爽:模块化,接口清晰,可替换,不膨胀。可以说这是一项内功。

grep — 在海量日志中捞出那根针

嵌入式开发最不缺的就是日志。内核启动、驱动加载、系统服务……它们一股脑涌向串口控制台或 /var/log/messages。你需要做的第一件事,就是把“噪音”过滤掉。

假设设备启动后网络异常,你想看看网卡有没有报错。不用打开一个完整的日志文件去翻,一条命令即可:

dmesg | grep -i "error\|fail\|warn"

grep -i 忽略大小写,\| 用来匹配多个关键词。管道那一头是 dmesg 的输出,这一头直接筛出所有包含 error、fail、warn 的行。几秒钟之内,你可能就会看到:

[   12.345678] fec 30be0000.ethernet: failed to get clock

线索瞬间浮现。你还可以用正则进一步精确过滤,比如只想看内存分配失败相关的内核错误,ENOMEM → 系统调用中内存分配失败的错误码(例如 mmap、malloc 失败)。:

dmesg | grep -E "Out of memory|ENOMEM"

这里的grep -E:使用扩展正则表达式(Extended regex)进行匹配,这就是 grep 给我们的核心能力:用极其低廉的代价,快速缩小问题域。在资源受限的板子上,你甚至不需要把日志保存成文件,串口输出一管,直接实时过滤,调试回路被压缩到最短。

sed — 无编辑器也能“原地生产”

嵌入式设备上修改配置是一个高频动作。网络参数、启动脚本、设备树覆盖项……但你的板子可能只有 BusyBox,没有你熟悉的编辑器。这时 sed 就是你的“流编辑器”,它不打开文件,却能瞬间完成修改。

比如你正通过串口调试网络,需要把 /etc/config/network 里的 IP 地址从 192.168.1.100 改为 192.168.2.100。不需要 vim,一行搞定:

sed -i 's/option ipaddr.*/option ipaddr 192.168.2.100/' /etc/config/network

-i 表示直接修改文件(BusyBox 的 sed 同样支持),s/old/new/ 做替换。你甚至可以用它来批量调整启动脚本,比如把所有打印调试信息的地方注释掉:

sed -i '/echo "DEBUG/s/^/#/' /etc/init.d/my_app

其中'/echo "DEBUG"/s/^/#/':一个完整的 sed 表达式,由“地址”和“命令”组成:

/echo "DEBUG"/:地址匹配条件。它会选中所有包含字符串 echo "DEBUG" 的行(注意双引号是字面匹配的一部分)。

s/^/#/:替换命令,将匹配行的行首(^)替换成 #,即在该行最前面插入注释符。

/etc/init.d/my_app:目标文件路径(通常是 System V init 风格的启动脚本)。

这种“无编辑器也能生产”的能力,在只有 initramfs 的紧急维护模式下尤其救命。它让你保持对系统的最小扰动——不需要挂载可写分区,不需要启动额外服务,只是让文本流经过一个规则,就完成了交付。

awk — 在管道中完成数据决策

awk 就是一把可以现场编程的瑞士军刀。它尤其擅长处理格式化的文本,比如 /proc 下的各种接口。

举个例子,你想快速查看当前中断的分布,找出哪个中断源最繁忙。/proc/interrupts 是这个样子的:

           CPU0       CPU1 29:      12345          0     GIC  29  arch_timer 37:       9876       1024     GIC  37  mmc0 44:          0      50000     GIC  44  eth0

用 awk 统计每个中断的总触发次数,并找出最高者:

awk 'NR>1 {sum=$2+$3; if(sum>max) {max=sum; name=$NF}} END {print name, max}' /proc/interrupts

解读一下:NR>1 跳过标题行,累加 CPU0 和 CPU1 的计数,通过比较找出最大值,最后打印中断名称和次数。执行结果可能就是 eth0 50000,直指问题核心。

再比如,你想在 shell 脚本里获取可用内存大小,而不用去写 C 解析 /proc/meminfo:

awk '/MemAvailable/ {print $2}' /proc/meminfo

/MemAvailable/:匹配包含 MemAvailable 的行,{print $2}:打印该行的第二个字段, 这就是我常说的“逻辑前移”——把数据处理直接前置到管道里。你不需要把数据拉到 PC 上用 Excel 画图,也不需要写一个独立的分析脚本。在数据产生的源头,一条 awk 命令就能把结论提取出来,直接用于下一步判断。这种即时反馈,让调试动作变得非常紧凑。

组合的力量:一条管道定位故障

单个工具已经足够锋利,但它们真正的威力,在组合时才会爆发。我曾经遇到一个案例:设备间歇性重启,日志滚动太快,串口记录也看不出规律。我用下面这条管道,在三十秒内锁定了嫌疑进程:

dmesg | grep -i "killed process" | sed 's/.*process //; s/(.*)//' | awk '{a[$1]++} END{for(i in a) print i, a[i]}' | sort -nrk2

我们拆解一下这个“文本流水线”:

  1. grep:从 dmesg 中捞出所有“killed process”的行,这通常是 OOM Killer 的输出。
  2. sed:用两次替换把进程名剥离出来,去掉乱七八糟的 pid 和括号。
  3. awk:用一个关联数组统计每个进程被杀死的次数。
  4. sort:最后按次数降序排列。

结果可能是一目了然的:

my_app 12log_server 3

那个被杀了 12 次的 my_app,显然就是内存泄漏的元凶。没有任何图形界面,没有安装任何分析工具,仅仅用板子上自带的命令,你就完成了一次完整的故障定位。这正是 Unix 哲学在嵌入式世界的最佳实践:让一个个单纯的小工具,通过管道组成解决复杂问题的临时团队。

个人感悟

在嵌入式 Linux 里摸爬滚打越久,越会敬畏“简单”。我们手中的板子可能跑不动 Python,可能连 gdb 都装不全,但 /bin 下的 grep、sed、awk 几乎永远都在。它们是 BusyBox 的一部分,是内核构建后默认存在的元素,是你最可信赖的原语。

养成这样的习惯:每当你想分析一个问题,先别急着写代码。试着在串口终端里用管道快速验证想法,把中间结果打印出来看一看。当假设被迅速证实,再把那行命令固化成脚本,放进产品的诊断工具里。这种工作流——假设 → 管道验证 → 固化——会极大地缩短你的调试回路。

最后你会发现,grep、sed、awk 已经不单是工具了,它们变成了你思维的一部分。遇到问题,你的第一反应会是如何用文本流去描述它、过滤它、提炼它。在资源极度受限的嵌入式世界里,这种思维不再束缚你。

最     后   

持续获取嵌入式实战干货,关注、标星 公众号不错过每一篇技术解析~

推荐好文点击蓝色字体即可跳转

☞专辑|Linux应用程序编程大全
☞ 专辑|学点网络知识
☞ 专辑|手撕C语言
☞专辑|手撕C++语言
☞ 专辑|经验分享
☞ 专辑|从单片机到Linux
☞ 专辑|电能控制技术
☞ 专辑|嵌入式必备数学知识

☞  MCU进阶专辑

☞  嵌入式C语言进阶专辑

☞  经验分享 

最新文章

随机文章