Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/shell/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 优化grep、awk和sed shell内容_Linux_Shell_Sed_Awk_Grep - Fatal编程技术网

Linux 优化grep、awk和sed shell内容

Linux 优化grep、awk和sed shell内容,linux,shell,sed,awk,grep,Linux,Shell,Sed,Awk,Grep,我试图对“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包含端口1

我试图对“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}'

grep1433 log.dat | awk'{for(i=1;i如果您使用的是gawk,您可以使用
\如果这些日志在一行上,您可以使用perl提取日志号并求和

perl -e '$f = 0; while (<>) {/.*LEN=([0-9]+).*/ ; $f += $1;} print "$f\n";' input.log
perl-e'$f=0;while(){/*LEN=([0-9]+).*/;$f+=$1;}打印“$f\n”;”input.log
我为糟糕的Perl道歉。我根本不是一个Perl人。

如果它真的需要优化,因为它运行得太慢了:你可能应该用一种更通用的语言来重写它。即使是AWK也可以,但对于长时间运行的提取器,我建议使用更接近Perl或Java的语言

您可以做的一个更改是,不要使用不必要的SED和第二个AWK调用,而是将端点移动到第一个AWK调用中,然后使用split()从LEN=num中提取数字,并将其添加到累加器中。类似split($i,x,“=”);sum+=x[2]


主要问题是您无法编写与…}匹配的awk'/LEN=(…)/{sum+=var.

因为我没有代表向Noufal Ibrahims答案添加注释,所以这里有一个使用Perl的更自然的解决方案

perl -ne '$sum += $1 if /LEN=(\d+)/; END { print $sum; }' log.dat

@Noufal您可以让perl完成所有艰苦的工作;)。

任何时候,只要在管道中有grep/sed/awk组合,就可以简化为单个awk或perl命令。下面是一个awk解决方案:

gawk -v dpt=1433 '
    $0 ~ dpt {
        for (i=1; i<=NF; i++) {
            if ($i ~ /^LEN=[[:digit:]]+/) {
                split($i, ary, /=/)
                sum += ary[2]
                next
            }
        } 
    } 
    END {print sum}
' log.dat
gawk-v dpt=1433'
$0~dpt{


对于(i=1;iI)将脚本更改为:>perl-e'$f=0;而(){if(/PT=1433/){/LEN=([0-9]+)/;$f+=$1;}}}打印“$f\n”| log.dat,现在我得到了正确的结果。随着| time,我得到了0.08s的差异。因此,我尝试使用perl和shell命令进行测试,如果i/O性能足够快,我看到perl的编译时间比shellcommand的运行时间慢。如果日志文件大小为7GB,perlcommand catch与shellcommand相同。因此我认为更好优化shellcommand。你是说对于较小的文件,perl命令速度较慢,只有在接近7GB时才能看到收益?我对这个结果感到非常惊讶,因为两个命令管道至少应该在文件中迭代两次。我尝试booth命令(使用65MB的文件)在使用fast SCSI设备的同一台机器上,shellcommand需要0.0287s,perl命令需要0.822s。在普通PC上进行相同的测试对perl更好,我认为这是因为servermachine上的fast I/O设备显示了perl的编译时间,并且编译了awk、sed、grep命令,这只是scrip中的真实运行时t、 shellscript的运行时中有一个0到多。shellcommand需要0.287s:-)抱歉,我不理解gawk语法,请解释一下好吗?我尝试grep'PT=1433'| gawk'\”'这是用于查找字符串的表达式,但如何对gawk命令中的字段求和?在我找到的文档中:\<匹配单词开头的空字符串。例如,/\Hey Charles,我用您的方法搜索解决方案,但我仍然找不到用\<保存For循环的方法。是否有任何方法可以搜索所有cols$1…$NF?他说y Charles thx用于您的“解决方案”,但它比我的第一个shell命令慢得多。此命令需要4.1秒,第一个解决方案只需要0.28秒,但当我将命令拆分为:grep'PT=1433'maiu kernel_log.dat | awk'{f=match($0,/LEN=[:digit:]+/);v=substr($0,RSTART+5,RLENGTH-6);s+=v;}END{print s;}“我需要0。367s@kockiren:你是如何对脚本计时的?我不明白这个命令。我尝试对变量$1求和,但这个变量仍然没有定义?!而且PT=1433也没有筛选器。你能解释一下如何使用你的“语法”吗?是的。我知道。它读起来太快了,我通常都会避免。不过这段代码很好。谢谢。+1’你这么说了吗您可以很快发表评论。:)我喜欢不可读的东西:-)但我不理解您的代码片段:-(n开关代表while?那么$1如何获得LEN=?$1是第一次捕获正则表达式的结果;在这种情况下,它将是LEN=。n开关导致perl包装您的代码(-e'code'))在使用输入行的while循环中,将其分配给$变量。使用-p而不是-n,将使其也打印该行。如果需要在该行上使用多个正则表达式,可以通过扩展If语句来完成;我使用了对LEN的直接抓取,因为我认为它是主要关注点。Perl非常适合此类任务但是要学会有效地使用还需要一点时间。另外,感谢Noufal:-)Thx为您的帖子,这就是我想要的。我正在寻找一个解决方案来保存第二个awk和sed命令。但我不知道如何保存。大多数类似的东西都可以在awk手册中找到。我实际上已经学会了,因为Perl“复制”这个想法,我知道lang就像我的后脑勺一样,呵呵。现在我将我的Shellcommand改为:grep'PT=1433'log.dat | awk'{for(I=1;isub()执行替换,工作方式有点像sed s//。使用split()而数组索引可能是最好的,除非性能是这样的开销,通过索引操作子字符串更有效(以避免regexp的成本)。如果性能如此关键,使用自定义C或ASM应用程序的IMHO可能是最好的。我有一个更好的解决方案,运行时为0.199sec grep'PT=1433'log.dat | awk'{for(i=1;iHey Glenn,谢谢你的代码片段,但速度太慢了。使用我的65MB日志文件进行测试需要4.122s,而且代码片段无法扩展到更大的文件,性能也更好。
gawk -v dpt=1433 '
    $0 ~ dpt {
        for (i=1; i<=NF; i++) {
            if ($i ~ /^LEN=[[:digit:]]+/) {
                split($i, ary, /=/)
                sum += ary[2]
                next
            }
        } 
    } 
    END {print sum}
' log.dat