You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Bash的AWK/SED/Grep解析对讲机只读通信日志并提取指定字段?

对讲机日志解析与实时监控解决方案

问题背景

我需要解析对讲机的只读通信日志,日志每条记录行数不固定(从2-3行到超8行都有),每条记录有固定起始标识received voice header from和结束标识%。折腾SED代码11小时都没搞定,现在想编写Bash脚本通过tail -fn0实时监控日志,提取指定6个字段,附上了尝试的脚本但没成功,同时想了解AWK、SED、Grep的适用场景和学习路径。

日志样例

M: 2019-06-08 18:15:24.927 DMR Slot 2, received network voice header from KS3X to TG 91
M: 2019-06-08 18:15:25.402 DMR Talker Alias (Data Format 1, Received 6/20 char): 'KS3X D'
M: 2019-06-08 18:15:25.410 DMR Slot 2, Embedded Talker Alias Header
M: 2019-06-08 18:15:25.412 0000: 04 00 68 4B 53 33 58 20 44 ..hKS3XD
M: 2019-06-08 18:15:26.111 DMR Talker Alias (Data Format 1, Received 13/20 char): 'KS3X DMR ID: '
M: 2019-06-08 18:15:26.120 DMR Slot 2, Embedded Talker Alias Block 1
M: 2019-06-08 18:15:26.121 0000: 05 00 4D 52 20 49 44 3A 20 *..MR ID: *
M: 2019-06-08 18:15:26.824 DMR Talker Alias (Data Format 1, Received 20/20 char): 'KS3X DMR ID: 1142129'
M: 2019-06-08 18:15:26.824 DMR Slot 2, Embedded Talker Alias Block 2
M: 2019-06-08 18:15:26.824 0000: 06 00 31 31 34 32 31 32 39 ..1142129
M: 2019-06-08 18:16:15.921 DMR Slot 2, received network end of voice transmission, 51.2 seconds, 0% packet loss, BER: 0.0%

需要提取的6个字段

  • 第一行from与to间的呼号(示例中为KS3X)
  • 第一行to到行尾的信道(示例中为TG 91)
  • 第8行末尾的DMR ID(示例中为1142129)
  • 第11行的通话时长(示例中为51.2 seconds)
  • 第11行的丢包率(示例中为0%)
  • 第11行的BER百分比(示例中为0.0%)

尝试的脚本

#!/bin/bash
ACCESS_TOKEN="o.WOgpVaaEBjoVLGKS3VzFnsO4xGClTRiF"
tail -fn0 /var/log/pi-star/MMDVM-2019-06-08.log | \
while read line ; do
echo "$line" | gawk '
match($0, /received.*voice header from ([[:alnum:]]+) to ([[:alnum:]]+ [0-9]+)/, a) {
    in_record = 1
    call_sign = a[1]
    channel = a[2]
}
in_record && match($0, /DMR ID: ([0-9]+)/, a) {
    dmr_id = a[1]
}
in_record && match($0, /([0-9.]+) seconds, ([0-9]+)% packet loss, BER: ([0-9.]+)%/, a) {
    in_record = 0
    print call_sign, channel, dmr_id, a[1], a[2], a[3]
}
'
done

可行解决方案

你的脚本思路没问题,但核心问题是单行处理的局限性——用while read line逐行传给gawk时,每次gawk只处理一行,之前存储的变量(比如call_sign、dmr_id)会在每次调用gawk时重置,无法跨行保留状态。

修改后的脚本直接让gawk处理整个日志流,就能持续跟踪记录状态:

#!/bin/bash
ACCESS_TOKEN="o.WOgpVaaEBjoVLGKS3VzFnsO4xGClTRiF"
tail -fn0 /var/log/pi-star/MMDVM-2019-06-08.log | gawk '
# 匹配记录起始行,初始化状态并提取呼号和信道
match($0, /received network voice header from ([[:alnum:]]+) to (TG [0-9]+)/, a) {
    in_record = 1
    call_sign = a[1]
    channel = a[2]
    dmr_id = ""  # 重置DMR ID,避免污染下一条记录
}

# 在记录内匹配完整的DMR ID行(防止中间行的部分内容干扰)
in_record && match($0, /DMR ID: ([0-9]+)'\''$/, a) {
    dmr_id = a[1]
}

# 匹配记录结束行,提取时长、丢包率、BER并输出所有字段
in_record && match($0, /received network end of voice transmission, ([0-9.]+) seconds, ([0-9]+)% packet loss, BER: ([0-9.]+)%/, a) {
    in_record = 0
    # 可选:确保所有字段都已提取,避免输出不完整记录
    if (call_sign != "" && channel != "" && dmr_id != "") {
        print call_sign, channel, dmr_id, a[1], a[2], a[3]
    }
}
'

关键调整点

  1. 去掉while read line + echo "$line" | gawk的组合,直接让gawk处理tail的输出流,保持变量跨行状态。
  2. 优化DMR ID匹配正则:/DMR ID: ([0-9]+)'\''$/——匹配行尾的单引号,确保只提取完整的ID行(避免中间行'KS3X DMR ID: '的干扰)。
  3. 增加dmr_id = ""重置逻辑,防止上一条记录的ID污染下一条。
  4. 可选的字段非空判断,避免输出不完整的记录。

AWK、SED、Grep适用场景梳理

Grep

  • 最适合:快速搜索匹配行、简单文本过滤/提取。比如找所有包含received voice header的行,或用-o提取特定匹配片段。
  • 不适合:复杂多字段提取、跨行处理、逻辑判断。

SED

  • 最适合:基于行的文本替换、简单行编辑(删除、插入、替换),适合批量修改文本内容。比如批量替换日志日期格式,或删除特定行。
  • 不适合:复杂状态跟踪、多字段关联提取(比如你的跨行日志解析场景),SED正则处理能力较弱,状态管理麻烦。

AWK

  • 最适合:结构化文本解析、多字段提取、跨行状态跟踪、逻辑判断、统计分析。像你的日志解析场景,需要跟踪一条记录的起始/中间/结束行,提取不同位置的字段,AWK的变量状态和模式匹配能力正好适配。
  • 不适合:简单单行替换(SED更高效)、纯搜索(Grep更快)。

学习建议

  • AWK:先掌握基础的模式-动作结构、变量使用、match()等核心函数,再练习状态跟踪和多文件处理,从日志解析、CSV处理等实际场景入手。
  • SED:重点学习基本命令(s替换、d删除、a插入)、正则语法和地址范围使用。
  • Grep:掌握常用选项(-i忽略大小写、-o只输出匹配部分、-v反向匹配、-E扩展正则)。

内容的提问来源于stack exchange,提问作者Jae Nulton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:26:06