Оптимизировать grep, awk и sed - PullRequest
2 голосов
/ 01 июня 2010

Я пытаюсь суммировать трафик различных портов в лог-файлах из "IPCop", поэтому я пишу и командую для своей оболочки, но я думаю, что можно оптимизировать команду.

Первая строка из моего лог-файла:

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 не находится в одном и том же положении все время.

Есть предложения по оптимизации этой команды?

С уважением Rene

Ответы [ 5 ]

5 голосов
/ 01 июня 2010

Поскольку у меня нет представителя для добавления комментария к ответу Нуфа Ибрагима, вот более естественное решение с использованием Perl.

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

@ Нуфал, вы можете заставить Perl выполнять всю тяжелую работу;).

3 голосов
/ 01 июня 2010

Если он действительно нуждается в оптимизации , так как он работает так невыносимо медленно: вам, вероятно, следует переписать его на языке более общего назначения. Даже AWK может это сделать, но я бы посоветовал что-то более близкое к Perl или Java для долго работающего экстрактора.

Одно изменение, которое вы можете сделать, вместо того, чтобы использовать ненужный SED и второй вызов AWK, переместить END в первый вызов AWK и использовать split (), чтобы извлечь число из LEN = num; и добавить его в аккумулятор. Что-то вроде split ($ i, x, "="); сумма + = х [2].

Основная проблема в том, что вы не можете написать awk '/LEN=(...)/ {sum + = var соответствуя ...}'.

2 голосов
/ 01 июня 2010

Каждый раз, когда у вас есть комбинации 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
1 голос
/ 01 июня 2010

Если вы используете gawk, вы можете использовать \<, чтобы избежать необходимости цикла for, функции match (-) для поиска подстроки "\ ", Т.е. поле, которое вы хотите, и substr для проецирования аргумента LEN. Затем вы можете использовать только один вызов awk, чтобы сделать все.

Постскриптум

Регулярное выражение, которое я дал выше, не работает, потому что символ = не является частью слова. Следующий скрипт awk работает:

/1433/ { f=match($0,/ LEN=[[:digit:]]+ /); v=substr($0,RSTART+5,RLENGTH-6); s+=v; }
END    { print "sum=" s; }
0 голосов
/ 01 июня 2010

Если они будут в одной строке, вы можете использовать perl для извлечения номеров LOG и суммирования.

perl -e '$f = 0; while (<>) {/.*LEN=([0-9]+).*/ ; $f += $1;} print "$f\n";' input.log

Я прошу прощения за плохой Perl. Я вообще не Perl.

...