GNU grep optimieren

8

Ich verwende egrep ( grep -E) mit einer PATTERN-Datei. ( -f path/to/file).

Dies geschieht in einer Endlosschleife in einem Textstrom. Dies bedeutet, dass ich nicht ALLE Eingaben auf einmal akkumulieren und an grep übergeben kann (wie *.log).

Gibt es eine Möglichkeit, grep dazu zu bringen, die NFA, die es erstellt, aus der PATTERN-Datei zu "speichern", um sie für die nächste Ausführung zu verwenden?

Ich habe Google durchsucht und die Dokumentation ohne Glück gelesen.

Ich werde versuchen, es ein bisschen mehr zu erklären. Ich muss eine feste Anzahl von Zeichenfolgen mit regulären Ausdrücken suchen (dies ist kein Teil einer Frage, kann aber gerne etwas anderes vorschlagen), z. B. IP-Adressen, Domains usw. Die Suche erfolgt in einem Feed aus dem Internet. Sie können sich das als Textstrom vorstellen. Ich kann nicht grepalle Eingaben verwenden, da es sich um einen Stream handelt. Ich kann einen Teil des Streams ansammeln und darauf verwenden grep(also nicht grepauf jeder Zeile), aber dies ist auch begrenzt (sagen wir für 30 Sekunden).

Ich weiß grep, dass eine NFA aus all ihren Mustern erstellt wird (in meinem Fall aus einer Datei). Meine Frage hier lautet also: Kann ich sagen grep, dass diese NFA für den nächsten Lauf gespeichert werden soll, da sie sich nicht ändern wird? Das würde mir jedes Mal die Zeit sparen, diese NFA aufzubauen.

bergerg
quelle
Was meinst du damit ? Dies geschieht in einer Endlosschleife in einem Textstrom ? Wollen Sie damit sagen, dass Sie eine greppro Textzeile ausführen? Woher kommt der Text? Wäre tail -feine Option?
Stéphane Chazelas
Nehmen wir an, ich sammle den Stream 30 Sekunden lang und laufe dann grepauf diesem Block.
Bergerg
1
Es ist immer noch nicht klar, warum Sie grepmehrmals laufen müssen . Möglicherweise verwandt: Warum ist das Abgleichen von 1250 Zeichenfolgen mit 90.000 Mustern so langsam?
Stéphane Chazelas
5
grepsoll an einem Textstrom arbeiten, ich verstehe immer noch nicht, warum Sie mehrere Instanzen ausführen müssen. Warum können Sie nicht alle derselben grepInstanz zuführen ? Warum müssen Sie sie ansammeln , bevor Sie sie füttern grep?
Stéphane Chazelas
2
Schauen Sie sich flex an und schreiben Sie Ihr eigenes Programm, das sich möglicherweise als viel schneller herausstellt.
user2064000

Antworten:

14

Nein, so etwas gibt es nicht. Im Allgemeinen grepwären die Kosten für den Start (Verzweigen eines neuen Prozesses, Laden der ausführbaren Datei, gemeinsam genutzte Bibliothek, dynamische Verknüpfung ...) viel höher als das Kompilieren der regulären Ausdrücke, sodass diese Art der Optimierung wenig Sinn macht.

Siehe Obwohl Warum ist passend 1250 Saiten gegen 90k Muster so langsam? über einen Fehler in einigen Versionen von GNU grep, der es für eine große Anzahl von regulären Ausdrücken besonders langsam machen würde.

Möglicherweise können Sie hier vermeiden, grepmehrmals zu laufen, indem Sie Ihre Chunks derselben grepInstanz zuführen , indem Sie sie beispielsweise als Co-Prozess verwenden und einen Marker verwenden, um das Ende zu erkennen. Mit zshund GNU grepund awkandere Implementierungen als mawk:

coproc grep -E -f patterns -e '^@@MARKER@@$' --line-buffered
process_chunk() {
  { cat; echo @@MARKER@@; } >&p & awk '$0 == "@@MARKER@@"{exit};1' <&p
}
process_chunk < chunk1 > chunk1.grepped
process_chunk < chunk2 > chunk2.grepped

Obwohl es vielleicht einfacher ist, das Ganze mit awkoder perlstattdessen zu machen.

Wenn Sie die grepAusgabe jedoch nicht benötigen , um für verschiedene Blöcke in verschiedene Dateien zu wechseln, können Sie immer Folgendes tun:

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output
Stéphane Chazelas
quelle
Ich habe Version 3+ von Grep, das ist also nicht das Problem. Ich habe nicht einmal an die Gabelung gedacht. Ich denke, ich werde versuchen, alles grepso zu streamen, wie es ist. Vielen Dank.
Bergerg
Würden die ausführbare Datei und die gemeinsam genutzten Bibliotheken nach Beendigung der Prozesse nicht in RAM-Puffern verbleiben (es sei denn, das OP verfügt tatsächlich über wenig RAM)?
Dmitry Grigoryev
2
@DmitryGrigoryev, ja, höchstwahrscheinlich muss noch im Prozessadressraum zugeordnet werden und die Linkbearbeitung durchgeführt werden. Es geht eher darum, die Gebietsschemadaten zu laden und zu analysieren, die Optionen und die Umgebung zu analysieren ... Der Punkt ist, dass die Kosten für regcomp () in all dem Aufwand verwässert werden. Das erste, was Sie bei der Optimierung tun müssen, ist zu vermeiden, dass zunächst mehrere Greps ausgeführt werden.
Stéphane Chazelas
1

Ich kann grep nicht für alle Eingaben verwenden, da es sich um einen Stream handelt. Ich kann einen Teil des Streams ansammeln und grep darauf verwenden ...

Ist Ihnen bewusst, dass Pipelines blockieren? Wenn Sie etwas an grep weiterleiten und nicht alle Eingaben verfügbar sind, wartet grep, bis es verfügbar ist, und fährt dann fort, als ob die Eingabe die ganze Zeit vorhanden wäre.

$ ( echo a1; echo b1; sleep 5; echo a2 ) | grep 'a.'
a1
a2

BEARBEITEN: Wie Pipelines funktionieren, ist zum Beispiel, cmd1 | cmd2dass beide Programme gleichzeitig gestartet werden, mit einem zB 65.536-Byte- "Chunk-Puffer" zwischen ihnen. Wenn cmd2versucht wird zu lesen und dieser Puffer leer ist, wartet er darauf, dass ein Block verfügbar ist. Wenn cmd1versucht wird zu schreiben und dieser Puffer voll ist, wartet er, bis er cmd2gelesen wird.

Nach allem, was ich lesen kann, besteht keine Notwendigkeit, die Eingabe in Stücke zu schneiden und sie separat an grep zu übergeben. Das geht schon automatisch.

EDIT2: grepsollte auch die Ergebnisse drucken, sobald sie im Stream gefunden werden. Der Stream muss nicht beendet werden, bevor Sie Ihre Ergebnisse erhalten können.

JoL
quelle
0

Vielleicht können Sie "grep für alle Eingaben verwenden"? Verwenden Sie nc(netcat) oder über scriptoder über andere ähnliche Tools? Besonders wenn Ihre Musterdatei eine überschaubare Größe hat (sagen wir weniger als 1000 reguläre Ausdrücke).

Erstes Beispiel : Sie können egrepeine Streaming-Verbindung herstellen: (hier Beispiel mit nc, aber andere könnten zutreffen)

prompt:/some/path $ nc somehost someport | egrep -f patternfile | gzip -c - > results.gz

# and while this is running, you can have a look at the growing results.gz:
prompt:/some/otherpath $ tail -f /some/path/results.gz | gzip -c - | less

(Hinweis: Sie können sogar: touch /some/path/results.gzvor dem Starten des ncBefehls tail -fin dieser (leeren) Datei nichts verpassen. Auf jeden Fall enthält die results.gz alles, was Sie abfangen wollten.)

zweites Beispiel : Sie könnten sogar egrepin einer aktuell ausgeführten Shell-Sitzung (und einen anderen Weg zeigen, um den Fortschritt zu verfolgen):

#in 1 terminal:
prompt:/home/userA $ script
Script command is started. The file is typescript.
prompt:/home/userA $ 
 ... doing here whatever you want (start IRC? etc) ...
prompt:/home/userA $ ctrl-d # to end the current script session
Script command is complete. The file is typescript.

#and in another terminal, while you are "doing here whatever you want" :
prompt:/home/somewhere $ tail -f /home/userA/typescript | egrep -f patternfile  | tee /some/place/to/store/results.gz

egrepist grepauf den meisten Systemen eine hocheffiziente Version von (siehe einige interessante Informationen unter: https://swtch.com/~rsc/regexp/regexp1.html )

Olivier Dulac
quelle
Sie könnten sogar exemple1 für Dinge wie eine dd-Ausgabe usw. verwenden.
Olivier Dulac
Interessante Randnotiz: grep ist effizienter, je größer der bekannte Teil des regulären Ausdrucks ist (z. B. das Suchen nach der Zeichenfolge oder dem regulären Ausdruck sist viel, Mush langsamer als das Matching somethingund dies ist viel langsamer als das Matching something even much longer(letzteres ermöglicht es dem regulären Ausdruck, größer zu werden) Teile der Eingabe, wenn sie unterschiedlich sind) Bei großen Dateien wird die Zeit zum Parsen im Grunde genommen durch das Längenverhältnis "geteilt" (dh das Erfassen eines bekannten Zeichens ist fast 40-mal langsamer als das Abgleichen einer Zeichenfolge mit 40 bekannten Zeichen. Ich habe es nicht getan). t prof es, aber es ist wirklich auffällig.)
Olivier Dulac