Kombinieren Sie mehrere Unix-Befehle zu einer Ausgabe

9

Ich muss unsere E-Mail-Protokolle nach einer bestimmten E-Mail-Adresse durchsuchen. Wir speichern eine aktuelle Datei mit dem Namen maillog sowie .bz2- Dateien im Wert von einer Woche im selben Ordner. Derzeit führe ich die folgenden Befehle aus, um nach der Datei zu suchen:

grep person@domain.com maillog
bzgrep person@domain.com *.bz2

Gibt es eine Möglichkeit, die Befehle grepund bzgrepin einer einzigen Ausgabe zu kombinieren ? Auf diese Weise könnte ich die kombinierten Ergebnisse an eine einzelne E-Mail oder eine einzelne Datei weiterleiten.

Ben McCormack
quelle

Antworten:

24

Ein anderer Weg ist

{ grep ...; bzgrep ...;} >file

&&hat die Schwierigkeit, dass das bzgrepnicht laufen würde, wenn das grepfehlschlägt.

Beachten Sie das obligatorische Leerzeichen nach der öffnenden geschweiften Klammer und das Semikolon nach dem letzten Befehl. Alternativ können Sie die Subshell-Syntax (Klammern anstelle von geschweiften Klammern) verwenden, die nicht so wählerisch ist:

(grep ...; bzgrep ...) >file
Geekosaurier
quelle
+1 für den besten allgemeinen Shell-Ansatz für dieses Problem. Die Shell-Gruppierung wird im Allgemeinen nicht ausreichend genutzt.
Phil Hollenback
2
Meinst du nicht ()statt {}?
Ehtesh Choudhury
Unter Arch Linux funktionierte dies ()aber nicht {}, so oder so +1, da dies das ist, was ich brauchte!
Chris Magnuson
11

bzgrep verwendet automatisch den Standardwert grep, wenn eine Datei nicht bzip-komprimiert ist. Daher sollte folgendes ausreichen:

bzgrep person@domain.com maillog *bz2 | mail -s "logs yay" someuser@blah

Oh, natürlich ist hier auch meine obligatorische GNU Parallel- Lösung:

parallel -m bzgrep person@domain.com ::: maillog* *bz2 | mail -s "logs yay" someuser@blah

Das könnte viel schneller sein, wenn Sie viele Dateien überprüfen.

Phil Hollenback
quelle
2

Hier ist eine andere Möglichkeit (vorausgesetzt, Sie führen Bash aus, was Sie wahrscheinlich sind):

cat <(bzgrep ...) <(grep ...)

Hier füttert bash die Ausgabe der Befehle bzgrep und grep transparent in cat, als wären sie Dateien (und sie befinden sich sozusagen unter der Haube, Details in der URL unten).

In Ihrem speziellen Fall würde ich Phils Lösung empfehlen, aber das oben Genannte ist ein guter Trick, um es in Ihrer Tasche zu behalten.

Wenn Sie interessiert sind, können Sie hier mehr lesen: http://www.tldp.org/LDP/abs/html/process-sub.html

Drew Bloechl
quelle
Ah ja, die kanonische Antwort für "Wie unterscheidet man die Ausgabe von zwei Prozessen?". Ein guter Trick zu wissen.
Phil Hollenback
1

Zum Zeitpunkt meines Schreibens war die Syntax der akzeptierten Antwort für die meisten, wenn nicht alle von Bourne abgeleiteten Shells falsch, einschließlich bash. Ich schlug oben eine Bearbeitung vor und akzeptierte die Antwort, um das zu beheben, aber ich war auch geneigt, all diese anderen Informationen hinzuzufügen, und dies wäre eher eine Neufassung als eine Bearbeitung gewesen.

Sie können zusammengesetzte Befehle verwenden:

{ grep ...; bzgrep ...; } >file

..oder Unterschalen (beachten Sie die Klammern anstelle der geschweiften Klammern):

(grep ...; bzgrep ...) >file

..um die Befehle zu gruppieren. Die Subshell-Methode hat eine schönere Syntax (mehr Verzeihung von Leerzeichen und das Weglassen des letzten Semikolons), aber sie gibt entweder einen neuen Prozess vor oder "tut" so, als würden die Befehle in einer bereinigten Umgebung ausgeführt. Beide haben Vorteile, je nachdem, was Sie tun möchten, was hier keine Rolle spielt, aber es lohnt sich, nachzuschauen, wenn Sie mehr Kenntnisse in der Shell wünschen.

Hinweis: Sie können Pipelining auch mit diesen Tricks verwenden, sodass Sie Folgendes tun können:

{ grep ...; bzgrep ...; } | less

PS: Wenn Sie sich nicht um die Reihenfolge der Übereinstimmungen in Ihrer kombinierten Ausgabe kümmern, können Sie einen einzelnen &zwischen den beiden Befehlen verwenden, z { grep ... & bzgrep ...; }. Dann werden die beiden Befehle gleichzeitig ausgeführt: Der grepwird gestartet und die Shell stellt ihn in den Hintergrund, dann führt die Shell den aus bzgrep. (Aber es gibt eine kleine Einschränkung, da die Erklärung der Dateiumleitung und der Pufferung von Dateistreams möglicherweise dazu führt, dass ein sehr kleiner Teil der Zeilen in der Ausgabedatei geteilt / verstümmelt wird: Ob dies angezeigt wird, hängt davon ab, wie Ihre grep, bzgrepund libc stdio.hFunktionen implementiert sind. In den meisten Implementierungen, glaube ich den Befehl kochend vor vermeidet das Problem in eine Datei umleiten, so dass Sie tun können , { foo & bar; } | cat - >filewie dieses Problem zu umgehen.)

mtraceur
quelle
0

Sie können die Befehle mit && verknüpfen, um jeden Befehl auszuführen.

Sie können auch >> textfile.txt am Ende jedes Befehls hinzufügen und die Ausgabe auf eine Datei treffen lassen und diese Datei dann per E-Mail versenden.

Mike
quelle
2
Wie der Geekosaurier erwähnte, sollte && hier nicht verwendet werden, da der Rückgabewert von grep davon abhängt, ob etwas gefunden wurde oder nicht. Wenn dies der grep ... && bzgrep ...Fall wäre und grep keine Treffer hätte, würde dies einen Fehler zurückgeben und der Befehl würde anhalten. >>ist jedoch eine gute Idee, im Gegensatz >dazu wird die Ausgabe am Ende einer vorhandenen Datei hinzugefügt.
DerfK
Richtig, ich hatte die Ausgangsbedingung vergessen, die den zweiten Befehl verhinderte.
Mike