开发时如果需要检索一段时间内或者某个批量执行期间的所有日志,也就是区间日志时,手动检索会有一些问题:
- 如要查询一段时间前的日志(比如归档日志),需要一页一页翻,费时且费眼睛
- 使用
grep
筛选日志,但是只能搜索满足特定字段的日志,无法检索区间日志
为了实现区间日志的检索,可以使用sed/awk
命令。这两个命令都无法直接处理压缩文件,需要先使用zcat
读取压缩文件再通过管道传递。
1 grep+sed
sed是一个流编辑器,它一次读取一行文本,处理一行并输出一行,要检索日志区间时,主要使用
-- 1.行号匹配,输出从startrow行到endrow行的内容
sed -n 'startrow,endrowp' filename
-- 2.字符匹配,输出从匹配start的行到end的行的内容
sed -n '/start/,/end/p' filename
行号匹配注意:
startrow,endrow
为起始行号,结束行号,p
为打印命令(print)sed
默认处理一行之后会输出一行,因此需要使用-n
+p
来取消自动打印,只打印我们需要的行- 如果只有一个行号,则打印指定行
- 打印到末尾,则区间为
startrow,$
字符匹配注意:
sed
匹配字符时,一旦匹配到start
则会一直输出内容直到匹配到end
,因此:
- 如果文件包含多个顺序
start...end
,则会分批输出 - 如果只有
start
,没有end
,则会从start
输出到文件末尾 - 如果文件内容为
start...start...end...end
,那么会输出从第一个start
到第一个end
区间里内容
匹配区间时候一般使用(真实使用这个最方便):
-- 1. 使用grep定位行号(如果是压缩文件,则使用zcat filename.tar.gz|grep -n "xxx")
grep -n "开始日志标志" filename
-- 2. 找到上述命令输出行号,比如 510:xxxxx,在该行号上面+大致区间长度即可,压缩文件同样使用zcat+管道
sed -n '510,550p' filename
2 awk
sed
一般只用于简单的文本转换编辑,比如查找替换,但awk
命令是一个更强大的文本处理器,可以处理更复杂的命令,比如计算、分析。
awk
采用“模式-动作”对执行模型,命令基本结构是:
pattern {action}
pattern {action}
...
对于输入流/文件里的每一行,awk
会依次检查每个pattern
,如果匹配成功,则执行对应的action
,如果某个action
之后的pattern
不需要继续匹配,则需在这个action
中加上next
终止后续匹配。如果action
缺失,则采用默认动作{print $0}
,打印当前整行。
如果要打印开始日志
到结束日志
中间的内容,使用如下命令,与sed
一样,如果文件包含多组开始日志...结束日志
,则会输出所有区间:
-- 模式使用'/xxx/'表明使用正则表达式模式
-- 1.1 不包括开始日志和结束日志行
awk '/开始日志/{flag=1;next} /结束日志/{flag=0} flag' filename
-- 1.2 包括开始日志和结束日志行
awk '/开始日志/{flag=1} flag; /结束日志/{flag=0}' filename
-- 2. 语法糖,打印从开始日志行到结束日志行内的所有内容(包括首尾两行)
awk '/开始日志/,/结束日志/' filename
命令1.1的流程为:
- 当匹配
开始日志
行时,将开关变量flag
置1
,然后执行next
跳过后续模式动作处理,直接读取下一行 - 假设下一行是中间行,那么前两个正则匹配模式都失败,进行第三个
flag
模式,这是一个表达式模式,检查flag
的值。当它非0或非空
时为true
,然后采用默认动作{print $0}
,打印当前整行,因此中间行能被打印 - 当匹配
结束日志
行时,开关变量flag
置0
,继续下一个模式,此时flag
表达式判断为false
,因此不打印
这个流程完成了从开始日志行到结束日志行之间内容的打印。1.2同样可以按照这个流程分析,它会打印包括开始日志行和结束日志行在内的所有区间内容。
命令2是范围模式,格式为pattern1,pattern2 {action}
,是一种特殊模式,它表示从第一次匹配pattern1的行开始,到第一次匹配pattern2的行结束,之间的所有行都执行action动作。action缺失则打印整行。
3 sed/awk查找特定重复区间
当某功能或任务执行多次时,可能有多个任务开始...任务结束
区间:
1: 任务开始
2: ...
10: 任务结束
11: xxxx
12: 任务开始
13: ...
22: 任务结束
...
3.1 查找第一个区间
sed/awk
查找第一个区间日志都是在输出完后退出,sed
使用q
,awk
使用exit
:
sed -n '/任务开始/,/任务结束/p; /任务结束/q' filename
awk '/任务开始/{flag=1} flag; /任务结束/{print;exit}' filename
awk '/任务开始/,/任务结束/; /任务结束/{exit}' filename
3.2 查找第n区间
如果想要找到第n
组日志可以用awk
定义计数器(sed
不支持复杂操作):
awk '/任务开始/{cnt++} cnt==2{print} /任务结束/ && cnt==2 {exit}' filename
3.3 最后一组/最新组
sed,awk
都是流处理,无法回溯信息,因此无法得知当前区间是否是最后一次,所以最新一组日志需要使用反转命令找第一次结束日志...开始日志
区间,再倒转即可。
tac filename | sed -n '/任务结束/,/任务开始/p; /任务开始/q' filename
tac filename | awk '/任务结束/{flag=1} flag; /任务开始/{flag=0;exit}' | tac
tac filename | awk '/任务结束/,/任务开始/; 任务开始/{exit}' | tac