2

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

Я написал это:

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 ответа4

3
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 .

1

Я так за это проголосую ...

#!/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;
1

Ваша команда немного хрупкая, так как она потерпит неудачу, если в имени файла будет пробел. В противном случае ваша команда на самом деле не так уж плохо. Это в некотором смысле дело вкуса, но я считаю, что цепочку простых командных команд гораздо проще поймать, чем одну сложную команду, такую как большой 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 behind (?<=) и прогноз ((?)=) чтобы изолировать совпадение с точным именем функции. Обратите внимание, что упреждения и упреждения имеют нулевую ширину, что означает, что они не считаются частью совпадения, но контролируют, каким будет совпадение. Поскольку совпадение теперь точно соответствует имени функции, мы можем использовать -o, чтобы сказать grep, что нужно печатать только совпадающую строку, а не всю строку. Я думаю, что вы должны оставить то, что у вас есть, если только вы не думаете, что имя файла с пробелами возможно.

0

Пока я на это

#!/bin/sh
grep -E '00[7-9]\.|0[1-9][0-9]\.' "$@" | awk '{print $6}' |
    sed 's/:$//' | sort | uniq -c | sort -rn

Исходная команда не так сложна, это повторение для каждого журнала, которое делает ее такой. Вставьте его в файл сценария (или функцию), назовите его sortbytime , и вот - у вас есть простая команда , состоящая из одного слова.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .