Ich habe unten zwei Befehle für sehr große Dateien ausgeführt
grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4
awk '/string1|string2/ && /string3/ && /string4/' 151103*.log
Die Ausführung dauerte fast genauso lange. Aber awk
es ging viel schneller, mir die passenden Ergebnisse anzuzeigen. grep
Auch hier wurde mir das gleiche Ergebnis angezeigt, aber am Ende, als der Vorgang abgeschlossen war.
Für die Ausführung beider Vorgänge wurde gleich viel Zeit benötigt. Ich möchte lediglich die Logik hinter den Suchvorgängen nach awk
und kennen grep
.
Warum ist es awk
schneller? Haben beide Programme eine unterschiedliche Suchlogik? Was ist, wenn ich die Zeichenfolgen in der obigen Suche durcheinanderbringe? Macht das einen Unterschied bei der Suchgeschwindigkeit?
Antwort1
GNU grep
puffert die Ausgabe, GNU jedoch awk
nicht. Und selbst wenn Sie GNU nicht verwenden würden, awk
sondern eine andere Variante, wäre es wahrscheinlich immer noch zeilengepuffert, wenn Sie auf einem Terminal drucken würden, und würde daher die Ausgabe für jede auftretende \n
Ewline leeren, aber Ihre grep
Schreibvorgänge erfolgen in eine Pipe und würden daher trotzdem blockgepuffert. Wenn Sie ein GNU haben, grep
können Sie es grep --line-buffered ... | grep ...
für Ihren Vergleich verwenden, um Ergebnisse so schnell wie möglich zu sehen. Wird wahrscheinlich bei praktisch jedem Match-Test grep
besser sein - insbesondere bei einem GNU .awk
grep
Hier können Sie sed
auch tun, was Sie möchten:
sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out
Antwort2
Die Grep-Pipeline konnte nichts ausgeben, bis das Finale grep
für string4 mit etwas übereinstimmte, und sie erhält ihre Eingabe erst, nachdem der vorherige Pipe-Puffer voll ist. Siehe verwandte FragenWie groß ist der Rohrpuffer?UndPufferung in der Pipe deaktivieren.
Abhängig von der Häufigkeit der Zeichenfolgen in Ihrer Eingabe können sich Unterschiede in den Laufzeiten ergeben, wenn Sie die statischen Suchvorgänge an den Anfang stellen, damit weniger auf die erweiterten regulären Ausdrücke geachtet werden muss.
Antwort3
Ihr awk-Beispiel führt die gesamte Regex-Suche in einem Durchgang durch. Wenn für jede Eingabezeile der erste, zweite und dritte Regex gefunden wird, wird die Zeile gedruckt und Sie sehen die Ausgabe im Wesentlichen sofort (nach der Verarbeitung der übereinstimmenden Zeile).
Ihr Grep-Beispiel verwendet drei verschiedene Aufrufe von Grep (einen für jeden regulären Ausdruck), um dasselbe zu tun, aber die Ausgabe jedes Aufrufs wird zur Eingabe für den nächsten, was bedeutet, dass jeder Aufruf abgeschlossen sein muss, bevor der nächste etwas zu verarbeiten hat.
Wenn Sie eine einzelne 1000-Zeilen-Datei hätten und nur Zeile 5 mit allen drei regulären Ausdrücken übereinstimmt, würde Ihnen der Befehl awk nach der Verarbeitung der 5. Zeile eine Ausgabe geben, bevor die 6. Zeile verarbeitet wird. Vergleichen Sie das mit den weitergeleiteten grep-Anweisungen. Der 1. Aufruf von grep würde die 5. Zeile und alle anderen Zeilen finden, die mit dem 1. regulären Ausdruck übereinstimmen, und nach der Verarbeitung der 1000. (letzten) Eingabezeile wird seine Ausgabe zur Eingabe für den 2. Aufruf von grep. Der zweite Aufruf von grep verarbeitet beliebig viele Zeilen der 1. Ausgabe und gibt die Zeilen aus, die sowohl mit dem 1. als auch mit dem 2. regulären Ausdruck übereinstimmen, die dann zur Eingabe für den 3. Aufruf von grep werden. Da der 3. Aufruf von grep jede Zeile verarbeitet, wird es jede Zeile ausgeben, die mit seinem regulären Ausdruck übereinstimmt.
Sie können die besten und schlechtesten Fälle von grep für das obige Beispiel vergleichen: Wenn keine der Zeilen mit einem der regulären Ausdrücke übereinstimmt, außer Zeile 5, die mit allen 5 übereinstimmt, verarbeitet das erste grep 1000 Zeilen, das zweite grep verarbeitet 1 Zeile und das dritte grep verarbeitet 1 Zeile: es werden 1002 Zeilen verarbeitet, bevor es eine Ausgabe hat (bester Fall). Wenn alle Zeilen mit den ersten beiden regulären Ausdrücken übereinstimmen, aber nur eine Zeile mit dem dritten regulären Ausdruck, verarbeitet die Piped-Grep-Konstruktion 1000 + 1000 Zeilen + 5 = 2005 Zeilen, bevor sie die Übereinstimmung in der 5. Zeile findet und eine Ausgabe hat (sie verarbeitet weiterhin die verbleibenden 995 Zeilen aus der Ausgabe des zweiten grep, aber Sie werden keine weitere Ausgabe sehen, weil nichts anderes übereinstimmt).
Vergleichen Sie das mit dem awk-Befehl, der alle drei regulären Ausdrücke gleichzeitig für jede Zeile prüft und Ihnen nach der Verarbeitung der 5. Zeile eine Ausgabe liefert. Der Unterschied wird noch deutlicher, wenn Sie mehr Dateien gleichzeitig prüfen.
Vergleichen Sie beispielsweise, ob die Ausgabe schneller erfolgt, wenn Sie den Befehl grep nicht wie oben beschrieben für alle Dateien gleichzeitig ausführen (theoretisch sollten Sie das tun, aber die Ergebnisse können je nach Verteilung der Treffer in Ihren Dateien unterschiedlich ausfallen):
grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4
Sie führen stattdessen die Reihe der Grep-Befehle für jede Datei einzeln aus, und zwar wie folgt:
for i in 151103*.log;
do grep -E 'string1|string2' $i |grep 'string3' | grep string4;
done
Dadurch wird die Ausgabe immer noch nicht so schnell erzeugt wie mit der awk-Anweisung, aber Sie werden möglicherweise einen Unterschied bemerken.
Antwort4
Obwohl grep, awk und sed für ähnliche Aufgaben verwendet werden können, hat jedes seine Stärken und Schwächen.
Awk eignet sich am besten für tabellarische Daten oder wenn Sie Berechnungen usw. durchführen müssen.
Sed zeichnet sich durch das Ersetzen von Text aus.
Grep eignet sich am besten zum Auswählen von Zeilen aus Eingabedaten, daher hatte ich erwartet, dass es für diese Aufgabe schneller ist als awk. Vielleicht sehen Sie das, wenn Sie die drei Grep-Befehle zu einem kombinieren. Im Moment ist Grep im Nachteil, da es dreimal gestartet werden muss und beim zweiten und dritten Mal auf die Eingabe des ersten gewartet werden muss. Das könnte erklären, warum das Ergebnis mit Verzögerung kommt. Obwohl ich mir da nicht sicher bin.