Hilf mir mit meinem Befehl (vor allem awk)

1212
Malfist

Ich habe gerade den am meisten verzerrten Befehl geschrieben, den ich je geschrieben habe, und ich möchte wissen, wie ich es verbessern kann.

Ich habe das geschrieben:

grep -E '00[7-9]\.|0[1-9][0-9]\.' filename.log | awk '' | sed 's/\(.*\):.*/\1/' | sort | uniq -c | sort -rn 

Eine beispielhafte Eingabe:

2011/06/30 07:59:43:81 20626 code_file.c (252): FunctionName: 009.63 seconds 

Im Grunde durchläuft es eine Protokolldatei, in der die Anzahl von Sekunden aufgeführt ist, die ein Befehl zum Ausführen benötigte, und von denen, deren Ausführung zwischen 7 und 99 Sekunden dauerte. Dann druckt awk das sechste Wort. Dies ist der Funktionsname, gefolgt von einem Doppelpunkt. Sed entfernt dann den Doppelpunkt und alle nachfolgenden Leerzeichen, dann wird es sortiert, gezählt und dann basierend auf seiner Zählung sortiert.

Ich arbeite mit HP-UX, daher sind einige meiner Tools begrenzt, aber ich weiß, dass awk das tun kann, was ich gerade mit sed gemacht habe. Kann mir jemand helfen, meinen Befehl zu komplizieren?

2
Eine beispielhafte Eingabezeile wäre hilfreich. grawity vor 12 Jahren 0
Sie haben erwähnt, dass Ihre Werkzeuge begrenzt sind. Können Sie das näher erläutern? Haben Sie beispielsweise Perl, weil die Antwort von Gravity in Perl ist? bbaja42 vor 12 Jahren 0
[Welches Betriebssystem * hat kein Perl?] (Http://perldoc.perl.org/perlhpux.html) grawity vor 12 Jahren 0
Ich habe perl Ich sage nur, dass die HP-UX-Tools häufig weniger Funktionen als ihr GNU-Counter-Teil haben. Beispielsweise fehlt dem HP-UX grep -rAB und vielen weiteren wichtigen Optionen, auch uniq -w usw. Malfist vor 12 Jahren 0

4 Antworten auf die Frage

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 

Ich bin immer noch erstaunt über die Anzahl der Menschen, die anscheinend glauben, dass Pattern Matching weder möglich ist awknoch möglich sedist. Daher müssen sie einen grepAufruf hinzufügen .

Möchten Sie das abbauen? Ich verstehe nicht ganz, was du tust. Malfist vor 12 Jahren 0
Erste Zeilengruppe: In jeder Zeile, die der regulären Ausprägung entspricht, teilen Sie Feld 6 in Doppelpunkte auf und erhöhen Sie einen Zähler basierend auf der ersten Komponente (dadurch wird Ihr `sed` dupliziert). (`awk`-Arrays ähneln eher Perl-Hashes oder Python-Diktaten als gewöhnliche Arrays.) Die zweite Zeilengruppe wird ausgeführt, nachdem alle Zeilen gelesen wurden, und druckt die Elemente und Zählungen im Array aus. dies ersetzt das `sort | uniq -c` Teil. Ich kann die Zeilen aufteilen und einige Kommentare hinzufügen. geekosaur vor 12 Jahren 0
1
grawity

Ich werde so dafür downvotiert werden ...

#!/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; 
Das ist kaum ein Befehl, oder? : p BloodPhilia vor 12 Jahren 0
@BloodPhilia: Die Hälfte der Befehle, die ich täglich benutze, sieht so aus. * (Die andere Hälfte ist bash und Python.) * Ich hätte es als "perl -ne" -Linie schreiben können, aber im Vergleich dazu wäre es fast unmöglich zu verstehen. grawity vor 12 Jahren 0
Perl könnte Superuser [jQuery] sein (http://meta.stackexchange.com/questions/19478/the-many-memes-of-meta/19492#19492). ;-) Patches vor 12 Jahren 2
1
frankc

Ihr Befehl ist etwas spröde, da er fehlschlägt, wenn der Dateiname ein Leerzeichen enthält. Ansonsten ist dein Befehl eigentlich nicht so schlecht. Es ist etwas Geschmackssache, aber ich finde, dass eine Kette von einfachen Pipe-Befehlen viel einfacher zu grokieren ist als ein komplexer Befehl, wie zum Beispiel der große Axt, den jemand gepostet hat. Es ist fast wahrscheinlich, dass die Programmierung in einem funktionalen Stil erfolgt.

Sie können jedoch den Grep ändern, um die awk und sed zu eliminieren, aber jetzt ist der Regex viel schwieriger zu verstehen:

 grep -P -o '(?<=\): ).+?(?=: 00[7-9]|0[1-9]|1)' | sort | uniq -c | sort -nr 

Um den Regex zu erklären, verwenden wir den Perl-Style re (-P param) und Looklook (? <=) Und Look-Ahead (? =), Um die Übereinstimmung mit dem Funktionsnamen genau zu isolieren. Beachten Sie, dass Look-Behind und Look-Ahead die Breite Null haben. Dies bedeutet, dass sie nicht als Teil des Matches betrachtet werden, sondern steuern, was das Match tatsächlich sein wird. Da die Übereinstimmung nun genau mit dem Funktionsnamen übereinstimmt, können Sie mit -o angeben, dass grep nur die übereinstimmende Zeichenfolge und nicht die gesamte Zeile druckt. Ich denke, Sie sollten das, was Sie haben, nicht verlassen, es sei denn, Sie denken, dass ein Dateiname mit Leerzeichen möglich ist.

0
grawity

Während ich dabei bin:

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

Der ursprüngliche Befehl ist nicht so kompliziert, es ist die Wiederholung jedes Protokolls, durch die es so aussieht. Stecken Sie es in eine Skriptdatei (oder eine Funktion), rufen Sie es auf sortbytime, und dort haben Sie einen einfachen Ein-Wort-Befehl.

Gibt es einen Grund, warum dies eine separate Antwort sein muss? nhinkle vor 12 Jahren 0
@nhinkle: Wahrscheinlich nicht. Fühlen Sie sich frei, um es zu löschen. (Ich sollte sie zusammenführen, aber ich kann das nicht mit dem Browser des Handys tun.) grawity vor 12 Jahren 0
Das sind zwei verschiedene Antworten. Wenn jemand dieses mochte und das andere nicht mochte, kann er auf diese Weise wählen. Wenn sie zusammengelegt wurden, konnten sie nicht. Es wäre alles oder nichts. Malfist vor 12 Jahren 0