bash脚本从大型日志文件中提取数据

时间:2020-05-20 01:40:12

标签: bash awk sed freebsd netscaler

我正在使用FreeBSD(在Citrix NetScaler上)……我面临的挑战是从具有几百行几千行的日志中提取Mbps。

日志看起来像这样,其中带十进制的Mbps数字范围可以从0.0到9999.99或更大。即

#>alphatext_anylength... (more_alphatext_in brackets)... Mbps (1.0)… alphatext_anylength... (more_alphatext_in brackets)... 
#>alphatext_anylength... (more_alphatext_in brackets)... Mbps (500.15)… alphatext_anylength... (more_alphatext_in brackets)... 
#>alphatext_anylength... (more_alphatext_in brackets)... Mbps (1500.01)… alphatext_anylength... (more_alphatext_in brackets)... 

现在的挑战是,我想过滤出所有Mbps括起来的数字,其小数位数A)大于500mbps,B)行号。也就是说,对于上面的示例输出,我只想查看以下内容:

#>[line number 20] 500.15
#>[line number 55] 1500.01

我尝试过:

cat output.log | sed -n -e 's/^.*Mbps//p' |cut -c 3-10

哪位在Mbps之后给了我10个字符。 但这还不够聪明,无法仅显示大于500Mbps的带括号的十进制数字。

如果遇到挑战,我可能会有点感激……但是,对于任何可以创建魔术的bash脚本向导,我们将不胜感激!

谢谢!

5 个答案:

答案 0 :(得分:1)

$ awk '{match($0,/Mbps \(([^)]*)\)/,a);if(a[1] > 500){print NR,a[1]} }' ./infile
2 500.15
3 1500.01

答案 1 :(得分:1)

使用三轮sed,(已通过 GNU sed测试,不确定它是否适用于 BSD sed) ,并且主要说明了为什么sed不是这项工作最简单的工具:

sed '=;s/.*).*(\([0-9.]*\)).*(.*/ \1/' output.log | 
sed ':a;s/[0-9]*/#>[line number &]/;N;s/\n//g;n;ba' | 
sed -n '/\b\([5-9]\|[0-9]\{2,\}\)[0-9]\{2,\}[^]]/p'

或者在不了解sed BSD \n上尝试(尝试尝试,因为我没有运行 BSD ) :

sed '=;s/.*).*(\([0-9.]*\)).*(.*/ \1/' output.log | 
sed ':a;s/[0-9]*/#>[line number &]/;N;s/
//g;n;ba' | 
sed -n '/\b\([5-9]\|[0-9]\{2,\}\)[0-9]\{2,\}[^]]/p'

输出:

#>[line number 2] 500.15
#>[line number 3] 1500.01

注意:为什么要进行三轮比赛?

  1. =输出当前行号,但是输出绕过任何行缓冲区,使行号在一次sed调用中不可见。

  2. =还会输出一个不需要的\n,而在sed中,这很容易消除。请参阅How can I replace a newline (\n) using sed?,其中显示了代码的工作原理。

  3. sed仅看到字符串,不知道数字,也不知道如何按值查找数字范围。参见Using sed to replace a number greater than a specified number at a specified position 关于我们如何伪造它。

答案 2 :(得分:1)

使用如下所示的括号,您可以将其用作awk的输入字段分隔符:

awk -F '[()]' '($4+0) > 500 {print FNR, $4}' file

您可能还需要检查$3以Mbps结尾:

awk -F '[()]' '($4+0) > 500 && $3~/Mbps *$/ {print FNR, $4}' file

答案 3 :(得分:0)

您可以使用awk来匹配包含Mbps (后跟任何非{)字符后跟)的行。 然后,使用空字符串替换直到Mbps (为止的字符串的开头,并且用空字符串替换直到末尾的)

如果转换为数字(+0)的其余行大于500,则打印行号和该行。

awk '
  /Mbps \([^)]*\)/{ sub(/.*Mbps \(/, ""); sub(/\).*/, "") }
  ($0+0) > 500{ print FNR, $0 }
' file

编辑:要匹配Mbps后包含值大于50的可选空格的行,请使用

awk '
  /Mbps ?\([^)]*\)/{ sub(/.*Mbps ?\(/, ""); sub(/\).*/, "") }
  ($0+0) > 50{ print FNR, $0 }
' file

答案 4 :(得分:0)

我改进了@Freddy的解决方案

awk '/Mbps.\(.*\)/{sub(/.*Mbps \(/, ""); sub(/\).*/, "")} ($0+0) > 500{print $0}' output.log

请给他点礼物:))