使用 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
比较强大,可以直接提取出字段信息,这里使用的是 gawk
,gawk
兼容 awk
语法,经测试,同样的语法 awk
无法满足需求,应该是 gawk
和 awk
实现有细微区别。
总结
如果仅仅是提取一个字段信息,三个工具都可以满足需求,相比起来,awk的功能更强大,完成字符串提取,grep
和 sed
的能力更多依赖正则表达式,如果需要同时处理一行记录中的多个字段,比如找出访问请求最长的 10 个 ip,grep
和 sed
就需要很复杂的正则表达式去匹配。