文章

使用 grep/sed/awk 提取字符串

使用 grep/sed/awk 提取字符串

原文: https://curryhuang.com/2015/07/18/extract-string-by-grep-sed-awk/

最近需要对日志进行分析,顺便学习了一下以前一直都没弄得太明白的awk和sed。

任务描述

日志是一个 tsv 文件,这里以 sample.log 为例,每一行大致长成下面这样,需要查看某个 api 的最长 10 次查询时间。根据记录格式,需要提取最后一个字段 ts= 之后的字符串,然后进行排序,排序和求 top 比较容易,sort -nr | head -n 10 即可,比较麻烦的是从字符串中提取数字。

1
2
#!shell
[2015-07-18 11:00:01,807]\t[service_name]\t[INFO]\t[172.0.0.1]\t[api/mock_api1]\t[ts=239]

解决方案

Google 了一番以后,发现 grep/sed/awk 均可以,下面分别说一下每一种方案。

以下方案均在CentOS6上测试通过

grep

1
2
3
4
#!shell
grep "api/mock_api1" sample.log |\
grep -Eo '\[ts=[0-9]+\]' |\
grep -Eo '[0-9]+'

grep 参数说明: E 使用正则表达式 o 只返回匹配的部分

分两部匹配,第一步提取出[ts=xxxx],第二步提取出数字

sed

1
2
3
4
#!shell
grep "api/mock_api1" sample.log |\
grep -Eo '\[ts=[0-9]+\]' |\
sed -r 's/\[ts=([0-9]+)\]/\1/g'

sed参数说明: r 使用正则表达式

使用 sed 也需要通过 grep 先匹配出最后一个字段,再使用 sed 提取数字部分,\1表示正则表达式中的分组1

gawk

1
2
3
#!shell
grep "api/mock_api1" sample.log |\
gawk -F'\t' 'match($6, /\[ts=([0-9]+)\]/, arr) { print arr[1] }'

gawk 参数说明: F 指定分隔符,这里指定为tab match 的函数参数分别为:待匹配字符串,模式,匹配后的字符串分组

awk 比较强大,可以直接提取出字段信息,这里使用的是 gawkgawk 兼容 awk 语法,经测试,同样的语法 awk 无法满足需求,应该是 gawkawk 实现有细微区别。

总结

如果仅仅是提取一个字段信息,三个工具都可以满足需求,相比起来,awk的功能更强大,完成字符串提取,grepsed 的能力更多依赖正则表达式,如果需要同时处理一行记录中的多个字段,比如找出访问请求最长的 10 个 ip,grepsed 就需要很复杂的正则表达式去匹配。

本文由作者按照 CC BY 4.0 进行授权