Помоги мне с моей командой (прежде всего, awk)

1160
Malfist

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

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

grep -E '00[7-9]\.|0[1-9][0-9]\.' filename.log | awk '' | 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. Может ли кто-нибудь помочь мне разобраться с моей командой?

2
Пример строки ввода будет полезен. grawity 13 лет назад 0
Вы упомянули, что ваши инструменты ограничены, вы можете уточнить? Например, поскольку ответ Gravity на perl, есть ли у вас perl? bbaja42 13 лет назад 0
[Какая ОС * не * имеет Perl?] (Http://perldoc.perl.org/perlhpux.html) grawity 13 лет назад 0
У меня есть Perl. Я просто заявляю, что инструменты HP-UX часто имеют меньшую функциональность, чем их контрагент GNU. Например, в grep HP-UX отсутствует -rAB и много других важных параметров, а также в uniq отсутствует -w и т. Д. Malfist 13 лет назад 0

4 ответа на вопрос

3
geekosaur
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вызовы.

Вы хотите это сломать? Я не до конца понимаю, что ты делаешь. Malfist 13 лет назад 0
Первый раздел: в любой строке, соответствующей регулярному выражению, разделите поле 6 на двоеточия и увеличьте счетчик на основе первого компонента (это дублирует ваш `sed`). (Массивы `awk` больше похожи на хеши Perl или предписания Python, чем на обычные массивы.) Вторая строфа выполняется после того, как все строки прочитаны, и распечатывает элементы и счетчики в массиве; это заменяет `sort | uniq -c` часть. Я могу разделить строки и добавить некоторые комментарии. geekosaur 13 лет назад 0
1
grawity

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

#!/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; 
Это вряд ли команда, а? :п BloodPhilia 13 лет назад 0
@BloodPhilia: Половина команд, которые я использую ежедневно, выглядит так. * (Другая половина - это bash и Python.) * Я мог бы написать это как однострочник `perl -ne`, но это было бы почти невозможно понять, в сравнении. grawity 13 лет назад 0
Perl может быть [jQuery] SuperUser (http://meta.stackexchange.com/questions/19478/the-many-memes-of-meta/19492#19492). ;-) Patches 13 лет назад 2
1
frankc

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

0
grawity

Пока я на это

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

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

Есть ли какая-то причина, по которой это должен быть отдельный ответ? nhinkle 13 лет назад 0
@nhinkle: Наверное, нет. Не стесняйтесь удалить его. (Я должен объединить их, но не могу сделать это с помощью браузера телефона.) grawity 13 лет назад 0
Это два разных ответа. Если кому-то это нравится, а другому не нравится, они могут голосовать таким образом. Если бы они были объединены, они не могли бы. Это было бы все или ничего. Malfist 13 лет назад 0