使用 awk 优雅地处理日志文件:从入门到实践
创作时间:
作者:
@小白创作中心
使用 awk 优雅地处理日志文件:从入门到实践
引用
1
来源
1.
https://jiejue.ai/2025/02/awk-log-processing-guide/
在日常工作中,我们经常需要处理各种格式的日志文件。有时候日志的格式并不理想,需要我们进行一些转换和处理才能更好地分析数据。本文将通过一个具体的应用场景,详细讲解如何使用awk这个强大的文本处理工具来优雅地处理日志文件。
问题场景
假设我们有一个应用程序生成的日志文件,每条记录包含了时间戳、事件类型、操作对象和相关进程信息。日志的原始格式如下:
2025-02-23 15:30:48.078 | Event: CREATE, Path: example.txt
相关进程:
AppOne(com.example.one)[最近活跃]
系统桌面(com.android.launcher)[最近活跃]
设置(com.android.settings)[最近活跃]
2025-02-23 15:31:01.218 | Event: MODIFY, Path: config.ini
相关进程:
AppTwo(com.example.two)[最近活跃]
系统桌面(com.android.launcher)[最近活跃]
...
这种格式虽然人眼容易读,但不利于我们用工具进行后续分析。我们希望:
- 过滤出特定文件的操作记录(比如只看 .txt 和 .ini 文件)
- 只保留第一个相关进程(通常是实际操作的进程)
- 将信息整理成表格形式,方便导入到其它工具处理
解决方案
让我们一步步来编写一个 awk 脚本来处理这个日志文件。
第一步:基本结构
首先,我们需要一个基本的脚本框架:
set raw_log my_app.log # 设置日志文件路径
awk '
BEGIN {
# 打印表头
printf("%-23s | %-12s | %-8s | %-20s | %s\n",
"TIMESTAMP", "EVENT", "PATH", "APP", "PACKAGE")
# 打印分隔线
printf("%.90s\n", "---")
}
# 后续处理逻辑会加在这里
' $raw_log
这个框架做了两件事:
- 定义了输出的表格结构
- 使用
printf
格式化输出,确保各列对齐
第二步:匹配关键行
接下来,我们需要找到包含我们感兴趣文件的行:
/Path:.*(txt|ini)/ { # 匹配包含 txt 或 ini 的 Path 行
# 保存这一行,后面会处理
event_line = $0
# 读取下一行
getline
if ($0 ~ /相关进程:/) { # 检查是否是进程信息行
getline # 再读取一行得到第一个进程
process = $0
# 后续处理...
}
}
这段代码:
- 使用正则表达式匹配包含指定文件类型的行
- 用
getline
读取后续行来获取进程信息 - 把需要的信息存储在变量中
第三步:提取信息
现在我们来提取需要的具体信息:
# 提取时间戳
timestamp = $1" "$2
# 提取事件类型
match($0, /Event: [^,]+/)
event_type = substr($0, RSTART+7, RLENGTH-7)
# 提取文件路径
match($0, /Path: [^ |]+/)
path = substr($0, RSTART+6, RLENGTH-6)
# 提取进程信息
match($0, /[^(]+\([^)]+\)/)
full_proc = substr($0, RSTART, RLENGTH)
split(full_proc, parts, "(")
app_name = parts[1]
package = substr(parts[2], 1, length(parts[2])-1)
这里使用了几个重要的 awk 函数:
match()
:在字符串中查找匹配的模式substr()
:提取子字符串split()
:分割字符串
第四步:格式化输出
最后,我们用格式化的方式输出提取的信息:
printf("%s | %-12s | %-8s | %-20s | %s\n",
timestamp, event_type, path, app_name, package)
格式说明:
%s
:字符串占位符-12s
:左对齐,宽度为12的字符串\n
:换行符
完整脚本
把上面的部分组合起来,这就是我们完整的处理脚本:
set raw_log my_app.log
awk '
BEGIN {
printf("%-23s | %-12s | %-8s | %-20s | %s\n",
"TIMESTAMP", "EVENT", "PATH", "APP", "PACKAGE")
printf("%.90s\n", "---")
}
/Path:.*(txt|ini)/ {
# 提取时间戳
timestamp = $1" "$2
# 提取事件类型
match($0, /Event: [^,]+/)
event_type = substr($0, RSTART+7, RLENGTH-7)
# 提取路径
match($0, /Path: [^ |]+/)
path = substr($0, RSTART+6, RLENGTH-6)
# 读取进程信息
getline
if ($0 ~ /相关进程:/) {
getline
# 提取进程名和包名
match($0, /[^(]+\([^)]+\)/)
full_proc = substr($0, RSTART, RLENGTH)
# 分割进程名和包名
split(full_proc, parts, "(")
app_name = parts[1]
package = substr(parts[2], 1, length(parts[2])-1)
# 输出格式化的日志
printf("%s | %-12s | %-8s | %-20s | %s\n",
timestamp, event_type, path, app_name, package)
}
}' $raw_log
运行这个脚本后,我们会得到这样的输出:
TIMESTAMP | EVENT | PATH | APP | PACKAGE
---
2025-02-23 15:30:48.078 | CREATE | test.txt | AppOne | com.example.one
2025-02-23 15:31:01.218 | MODIFY | app.ini | AppTwo | com.example.two
实用技巧
测试正则表达式 :在编写复杂的正则表达式时,可以先用
echo
和grep
测试:echo "your test string" | grep "your regex"
调试输出 :在开发过程中,可以使用
print
语句来调试:print "Debug:", $0 # 打印当前行
保存中间结果 :处理大文件时,可以先处理一小部分来测试:
head -n 100 big_log.txt | awk '你的脚本' > test_output.txt
小结
通过这个例子,我们学会了:
- 使用 awk 的基本语法和函数
- 如何处理多行日志记录
- 如何提取和格式化输出信息
这个脚本可以作为一个模板,通过修改正则表达式和输出格式,很容易适配其他类似的日志处理需求。希望这个教程能帮助你更好地理解和使用 awk 来处理日志文件。
热门推荐
美国留学生活中社交障碍的原因与应对策略
海南十大特色名小吃,你尝过几类?
微信接收消息为何静悄悄?揭秘无声背后的秘密
监听监控犯法吗:法律视角下的合法性与边界探讨
监控设备类型大比拼:你真的了解它们吗?
北京限行政策有哪些?这些政策对市民出行有何影响?
2024三国杀年度盛典在杭举办 千人沉浸式体验策略桌游竞技魅力
依恋关系的游戏治疗和辅导
怎么老照片在线修复免费?试试这6个老照片修复软件
三大保护铸就“美丽三清”
秋季气候干燥,六招呵护咽喉,畅享舒适生活!
尼龙固色剂材料物质成分配方分析检测及应用
如何衡量客户风险管理
信号的噪声处理及降噪方法
Chinoiserie风格——东西文化交融在艺术史中的表现
汽车前后轮胎压多少合适?前后轮胎压不一样吗
老年人房颤怎么办
深度解析:如何打造高效美观的后台网页设计
Web前端美化指南:从CSS到响应式设计的全方位实用技巧
法国税收及关税政策
发烧过后鼻翼周围出现小泡泡是什么原因
西安交大口腔医院刘瑾:牙周病需终身维护 定期检查是关键
郑钦文破发孙璐璐 晋级16强展现实力
郑钦文今年22岁,目前世界排名第7位,冲击世界第1近在咫尺
日工资怎么计算
住宅门前摆放石狮子有什么讲究?有何寓意?
性别平等视角下的妇女定义及其地位变迁
治疗肩周炎最佳运动是什么
AI文豪:未来文学的新篇章
公司商业秘密保护五大实用措施