Połącz wiele poleceń uniksowych w jedno wyjście

9

Muszę przeszukać nasze dzienniki poczty w celu znalezienia określonego adresu e-mail. W tym samym folderze przechowujemy bieżący plik o nazwie maillog, a także tygodniowe pliki .bz2. Obecnie uruchamiam następujące polecenia, aby wyszukać plik:

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

Czy istnieje sposób na połączenie poleceń grepi bzgrepw jedno wyjście? W ten sposób mogłem przesłać połączone wyniki do jednego e-maila lub pojedynczego pliku.

Ben McCormack
źródło

Odpowiedzi:

24

Innym sposobem jest

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

&&ma trudność z tym, bzgrepże nie można uruchomić, jeśli się grepnie powiedzie.

Zwróć uwagę na obowiązkowe odstępy po otwierającym nawiasie klamrowym i średniku po ostatnim poleceniu. Alternatywnie możesz użyć składni podpowłoki (nawiasy zamiast nawiasów klamrowych), co nie jest tak wybredne:

(grep ...; bzgrep ...) >file
geekozaur
źródło
+1 za najlepsze podejście powłoki do tego problemu. Grupowanie powłok jest zasadniczo niewykorzystaną funkcją.
Phil Hollenback,
2
Nie masz na myśli ()zamiast {}?
Ehtesh Choudhury,
Na arch. Linuxie to działało, ()ale nie {}, tak czy inaczej +1, ponieważ tego właśnie potrzebowałem!
Chris Magnuson
11

bzgrep automatycznie ustawia domyślnie na zwykły grep, jeśli plik nie jest skompresowany. Dlatego wystarczające powinny być:

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

och, oczywiście również tutaj jest moje obowiązkowe rozwiązanie GNU Parallel :

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

co może być znacznie szybsze, jeśli sprawdzasz wiele plików.

Phil Hollenback
źródło
2

Oto inny sposób na zrobienie tego (zakładając, że używasz basha, którym prawdopodobnie jesteś):

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

Tutaj bash w przejrzysty sposób podaje dane wyjściowe poleceń bzgrep i grep do cat, tak jakby były plikami (i jakby znajdowały się pod maską, szczegóły w url na dole).

W twoim szczególnym przypadku poleciłbym rozwiązanie Phila, ale powyższe jest dobrą sztuczką, aby trzymać w torbie.

Jeśli jesteś zainteresowany, możesz przeczytać więcej tutaj: http://www.tldp.org/LDP/abs/html/process-sub.html

Drew Bloechl
źródło
Ach tak, kanoniczna odpowiedź na pytanie „w jaki sposób różnicujesz wynik dwóch procesów”. Dobra sztuczka, aby wiedzieć.
Phil Hollenback,
1

W chwili pisania tego tekstu składnia zaakceptowanej odpowiedzi była niepoprawna dla większości, jeśli nie wszystkich, powłok pochodzących od Bourne'a, w tym bash. Zasugerowałem edycję na górze i zaakceptowałem odpowiedź, aby to naprawić, ale byłem również skłonny dodać te wszystkie inne informacje, a byłoby to raczej przepisanie zamiast edycji.

Możesz użyć poleceń złożonych:

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

.. lub podpowłoki (zwróć uwagę na nawiasy zamiast nawiasów klamrowych):

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

.. aby zgrupować polecenia. Sposób podpowłoki ma ładniejszą składnię (bardziej wybaczające brak białych znaków i pozwala pominąć ostatni średnik), ale albo forksuje nowy proces, albo „udaje”, że uruchamia polecenia w oczyszczonym środowisku. Oba mają zalety w zależności od tego, co chcesz zrobić, co nie ma tutaj znaczenia, ale warto spojrzeć w górę, jeśli chcesz więcej umiejętności posługiwania się powłoką.

Uwaga: z tymi sztuczkami możesz również korzystać z potokowania, dzięki czemu możesz zrobić coś takiego:

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

PS jeśli nie dbają o uporządkowaniu meczów w swojej połączonej mocy, można użyć pojedynczego &pomiędzy dwoma poleceniami, tak: { grep ... & bzgrep ...; }. Następnie dwa polecenia działają jednocześnie: grepuruchamia się, a powłoka umieszcza je w tle, a następnie powłoka uruchamia bzgrep. (Ale jest z tym małe zastrzeżenie, z wyjaśnieniem dotyczącym przekierowania pliku i buforowania strumienia plików, które potencjalnie mogą spowodować, że bardzo mała część wierszy w pliku wyjściowym zostanie podzielona / zniekształcona: czy zobaczysz, że to zależy od tego, w jaki sposób grep, bzgrep, a libc stdio.hfunkcje są zaimplementowane. W większości implementacji uważam, że przekazanie polecenia przed przekierowaniem do pliku pozwoli uniknąć problemu, więc możesz to zrobić { foo & bar; } | cat - >filejako obejście).

mtraceur
źródło
0

Możesz powiązać polecenia razem z &&, co pozwoli ci uruchomić każde polecenie.

możesz także dodać >> textfile.txt na końcu każdego polecenia i spowodować, że wynik trafi do pliku, a następnie wyśle ​​go pocztą.

Mikrofon
źródło
2
Jak wspomniano geekozaur, nie należy tutaj używać &&, ponieważ wartość zwracana przez grep zależy od tego, czy coś znalazł. Jeśli to zrobisz grep ... && bzgrep ..., jeśli grep nie będzie miał żadnych trafień, zwróci błąd i polecenie przestanie działać. >>jest dobrym pomysłem, w przeciwieństwie do >tego, doda dane wyjściowe na końcu istniejącego pliku.
DerfK,
właśnie zapomniałem o warunku wyjścia uniemożliwiającym drugie polecenie.
Mike