我创建了一个脚本,它将自动登录到路由器并检查当前的CPU负载,如果负载超过某个阈值我需要它将当前CPU值打印到标准输出。
我想在脚本o / p中搜索某个模式(在这种情况下,值80是高CPU负载的阈值),然后对于模式的每个实例,它将检查当前值是否大于是否为80,如果为真,那么它将在模式之前打印5行,然后打印带有模式的当前行。
问题1:如何循环遍历模式的每个实例并分别在每个模式上应用一些代码?
问题2:如何在模式之前打印n行,然后在模式之后打印x行?
离。我使用awk搜索模式“health”并在其后面打印6行:
awk '/health/{x=NR+6}(NR<=x){print}' ./logs/CpuCheck.log
我想对模式“80”做同样的事情,这次在它之前打印5行,在此之后打印一行......只有当$ 3(表示当前CPU负载)超过80时
下面是自动登录脚本的输出(文件名:CpuCheck.log)
ABCD-> show health xxxxxxxxxx
* - current value exceeds threshold
1 Min 1 Hr 1 Hr
Cpu Limit Curr Avg Avg Max
-----------------+-------+------+------+-----+----
01 80 39 36 36 47
WXYZ-> show health xxxxxxxxxx
* - current value exceeds threshold
1 Min 1 Hr 1 Hr
Cpu Limit Curr Avg Avg Max
-----------------+-------+------+------+-----+----
01 80 29 31 31 43
提前感谢您的帮助
答案 0 :(得分:2)
您可以使用-B
和-A
并切换到grep,而不是使用awk,grep会在匹配模式之前和之后打印多行:
grep -E -B 5 -A 1 '^[0-9]+[[:space:]]+80[[:space:]]+(100|9[0-9]|8[1-9])' CpuCheck.log
模式匹配以某些数字开头的行,后跟空格,后跟80,后跟81到100之间的数字。-E
开关启用扩展正则表达式(ERE),如果需要您希望使用+
字符表示“一个或多个”。如果您的grep版本不支持ERE,则可以使用稍微更详细的\{1,\}
语法:
grep -B 5 -A 1 '^[0-9]\{1,\}[[:space:]]\{1,\}80[[:space:]]\{1,\}\(100\|9[0-9]\|8[1-9]\)' CpuCheck.log
如果grep不是一个选项,一种替代方法是使用awk。最简单的方法是将所有行存储在缓冲区中:
awk 'f-->0;{a[NR]=$0}/^[0-9]+[[:space:]]+80[[:space:]]+(100|9[0-9]|8[1-9])/{for(i=NR-5;i<=NR;++i)print i, a[i];f=1}'
这会将每一行存储在数组a
中。当第三列大于80时,它将打印阵列中的前5行。它还将标志f
设置为1,以便f-->0
对于下一行为真,从而导致它被打印。
最初我选择了比较$3>80
而不是正则表达式,但由于行的格式不同,这不是一个好主意。
如果日志文件非常大,意味着将整个内容读入内存是不可行的,您可以实现循环缓冲区,以便只存储前5行,或者读取文件两次。
答案 1 :(得分:1)
不幸的是,awk
是面向流的,并没有一种简单的方法来获取当前行之前的行。但这并不意味着它是不可能的:
awk '
BEGIN {
bufferSize = 6;
}
{
buffer[NR % bufferSize] = $0;
}
$2 == 80 && $3 > 80 {
# print the five lines before the match and the line with the match
for (i = 1; i <= bufferSize; i++) {
print buffer[(NR + i) % bufferSize];
}
}
' ./logs/CpuCheck.log
答案 2 :(得分:1)
我认为使用awk最简单的方法是通过读取文件。 除了用于存储行号的内容之外,这应该基本上使用0个内存。
如果只有一次出现
awk 'NR==FNR&&$2=="80"{to=NR+1;from=NR-5}NR!=FNR&&FNR<=to&&FNR>=from' file{,}
如果有多个出现
awk 'NR==FNR&&$2=="80"{to[++x]=NR+1;from[x]=NR-5}
NR!=FNR{for(i in to)if(FNR<=to[i]&&FNR>=from[i]){print;next}}' file{,}
Input
1
2
3
4
5
6
7
8
9
10
11
12
01 80 39 36 36 47
13
14
15
16
17
01 80 39 36 36 47
18
19
20
Output
8
9
10
11
12
01 80 39 36 36 47
13
14
15
16
17
01 80 39 36 36 47
18
NR==FNR&&$2=="80"{to[++x]=NR+5;from[x]=NR-5}
在第一个文件中,如果第二个字段是80,设置为和从记录号+或 - 任何你想要的。 增加出现变量x。
NR!=FNR
在第二个文件中
for(i in to)
每次出现
if(FNR<=to[i]&&FNR>=from[i]){print;next}
如果当前记录编号(在此文件中)介于此次出现之间,则打印该行。如果模式的出现位置靠近,则会阻止多次打印该行。
file{,}
将文件两次用作两个参数。 {,}
扩展为file file