Помоги мне с моей командой (прежде всего, awk)
Я только что написал самую искаженную команду, которую я когда-либо писал, и я хочу знать, как я могу сделать это лучше.
Я написал это:
grep -E '00[7-9]\.|0[1-9][0-9]\.' filename.log | awk '{print $6}' | sed 's/\(.*\):.*/\1/' | sort | uniq -c | sort -rn
Пример ввода:
2011/06/30 07:59:43:81 20626 code_file.c (252): FunctionName: 009.63 seconds
По сути, он просматривает файл журнала, в котором указано количество секунд, которое потребовалось команде для выполнения, и захватывает любую из них, выполнение которой занимает от 7 до 99 секунд. Затем awk печатает шестое слово, которое является именем функции, за которым следует двоеточие. Затем sed удаляет двоеточие и все оставшиеся пробелы, затем сортируется, подсчитывается, а затем сортируется по количеству.
Я использую HP-UX, поэтому некоторые из моих инструментов ограничены, но я знаю, что awk может делать то же, что я только что сделал с sed. Может ли кто-нибудь помочь мне разобраться с моей командой?
4 ответа
awk '/00[7-9]\.|0[1-9][0-9]\./ { # for lines matching the regex
split($6, c, /:/) # take the part of field 6 before the colon
cs[ c[1] ]++ # and increment the counter for that string
}
END { # after all lines have been read
for (c in cs) { # step through the counters
print cs[c], c # and output the count followed by the string
# ("," adds a space automatically)
}
}' filename.log | sort -rn # standard awk doesn't support sorting, sadly
Я продолжаю удивляться количеству людей, которые, по-видимому, считают, что ни awk
ни sed
может сделать сопоставление с образцом, поэтому они должны добавить grep
призывание.
Я так за это проголосую...
#!/usr/bin/env perl
use strict;
my %counts;
while (my $line = <>) {
my @line = split(/\s+/, $line);
if ($line[6] >= 7) {
$line[5] =~ /(.+):/ and $counts{$1}++;
}
}
my @sorted = sort {$counts{$b} <=> $counts{$a}} keys %counts;
printf("%7d\t%s\n", $counts{$_}, $_) for @sorted;
Ваша команда немного хрупкая, так как она потерпит неудачу, если в имени файла будет пробел. В противном случае ваша команда на самом деле не так уж плохо. Это в некотором смысле дело вкуса, но я считаю, что цепочку простых командных команд гораздо проще поймать, чем одну сложную команду, такую как большой awk, который кто-то написал. Это скорее всего программирование в функциональном стиле.
Однако вы можете изменить grep, чтобы исключить awk и sed, но теперь регулярное выражение гораздо сложнее понять:
grep -P -o '(?<=\): ).+?(?=: 00[7-9]|0[1-9]|1)' | sort | uniq -c | sort -nr
Чтобы объяснить регулярное выражение, мы используем perl style re (-P param) и используем look back (? <=) И упреждающий просмотр (? =), Чтобы изолировать совпадение в точности до имени функции. Обратите внимание, что упреждения и упреждения имеют нулевую ширину, что означает, что они не считаются частью совпадения, но контролируют, каким будет совпадение. Поскольку совпадение теперь точно соответствует имени функции, мы можем использовать -o, чтобы сказать grep, что нужно печатать только совпадающую строку, а не всю строку. Я думаю, что вы должны оставить то, что у вас есть, если только вы не считаете возможным имя файла с пробелами.
Пока я на это
#!/bin/sh
grep -E '00[7-9]\.|0[1-9][0-9]\.' "$@" | awk '{print $6}' |
sed 's/:$//' | sort | uniq -c | sort -rn
Оригинальная команда не так сложна, это повторение для каждого журнала, которое делает ее такой. Вставьте его в файл сценария (или функцию), вызовите его sortbytime
и там - у вас есть простая команда из одного слова.