优化 grep、awk 和 sed shell 内容
我尝试对来自“IPCop”的日志文件中不同端口的流量进行求和,因此我为我的 shell 编写和命令,但我认为可以优化该命令。
首先是我的日志文件中的一行:
01/00:03:16 kernel INPUT IN=eth1 OUT= MAC=xxx SRC=xxx DST=xxx LEN=40 TOS=0x00 PREC=0x00 TTL=98 ID=256 PROTO=TCP SPT=47438 DPT=1433 WINDOW=16384 RES=0x00 SYN URGP=0
现在我用以下命令 grep 包含端口 1433 的所有长度的总和
grep 1433 log.dat|awk '{for(i=1;i<=10;i++)if($i ~ /LEN/)print $i};'|sed 's/LEN=//g;'|awk '{sum+=$1}END{print sum}'
我需要 for 循环,因为 LEN-col 并不始终处于同一位置。
有什么优化这个命令的建议吗?
问候 雷内
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
由于我没有代表向 Noufal Ibrahims 答案添加评论,因此这里有一个使用 Perl 的更自然的解决方案。
@Noufal,你可以让 perl 完成所有艰苦的工作;)。
Since I don't have the rep to add a comment to Noufal Ibrahims answer, here is a more natural solution using Perl.
@Noufal you can can make perl do all the hard work ;).
如果它确实需要优化,因为它运行得慢得难以忍受:您可能应该用更通用的语言重写它。即使 AWK 也可以,但我建议使用更接近 Perl 或 Java 的东西来实现长时间运行的提取器。
您可以进行的一个更改是,不要使用不必要的 SED 和第二个 AWK 调用,而是将 END 移到第一个 AWK 调用中,并使用 split() 从 LEN=num; 中提取数字;并将其添加到累加器中。像 split($i, x, "="); 之类的东西总和 += x[2]。
主要问题是你不能写 awk '/LEN=(...)/ { sum += var matches the ... }'。
If it really needs optimization, as in it runs so unbearably slow: you should probably rewrite it in a more general purpose language. Even AWK could do, but I'd suggest something closer to Perl or Java for a long running extractor.
One change you could make is, rather than using an unnecessary SED and second AWK call, move the END into the first AWK call, and use split() to extract the number from LEN=num; and add it to the accumulator. Something like split($i, x, "="); sum += x[2].
The main problem is you can't write awk '/LEN=(...)/ { sum += var matching the ... }'.
只要管道中有 grep/sed/awk 组合,您就可以简化为单个 awk 或 perl 命令。这是一个 awk 解决方案:
Any time you have grep/sed/awk combinations in a pipeline, you can simplify into a single awk or perl command. Here's an awk solution:
如果您使用 gawk,则可以使用” ",即投影出您想要的字段,并使用 substr 投影出 LEN 的参数。然后,您可以仅使用单个 awk 调用来完成所有操作。
\<
来避免使用 for 循环、match(-) 函数来查找子字符串“\后记
我上面给出的正则表达式不起作用,因为 = 字符不是单词的一部分。以下 awk 脚本确实有效:
If you are using gawk, you can use
\<
to avoid the need for the for-loop, the match(-) function to find the substring "\<LEN=.*\>", i.e., projecting out the field you want, and substr to project out the argument of LEN. You can then use just the single awk invocation to do everything.Postscript
The regexp I gave above doesn't work, because the = character is not part of a word. The following awk script does work:
如果它们在一行上,您可以使用 perl 提取 LOG 数字并将其相加。
我为糟糕的 Perl 表示歉意。我根本不是 Perl 人。
If these will be on a single line, you can use perl to extract the LOG numbers and sum it.
I apologise for the bad Perl. I'm not a Perl guy at all.