Grep tylko pierwszy mecz i zatrzymaj się

328

Przeszukuję katalog rekurencyjnie za pomocą grep z następującymi argumentami, mając nadzieję, że zwrócę tylko pierwsze dopasowanie. Niestety zwraca więcej niż jeden - w rzeczywistości dwa, kiedy ostatnio patrzyłem. Wygląda na to, że mam zbyt wiele argumentów, zwłaszcza bez uzyskania pożądanego rezultatu. : - /

# grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/directory

zwroty:

Pulsanti Operietur
Pulsanti Operietur

Może grep nie jest najlepszym sposobem na zrobienie tego? Bardzo mi dziękujesz.

Tim Kamm
źródło

Odpowiedzi:

510

-m 1oznacza zwrócenie pierwszego dopasowania w danym pliku. Ale nadal będzie wyszukiwać w innych plikach. Ponadto, jeśli w tym samym wierszu są dwa lub więcej pasujących, wszystkie zostaną wyświetlone.

Możesz użyć, head -1aby rozwiązać ten problem:

grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -1

wyjaśnienie każdej opcji grep:

-o, --only-matching, print only the matched part of the line (instead of the entire line)
-a, --text, process a binary file as if it were text
-m 1, --max-count, stop reading a file after 1 matching line
-h, --no-filename, suppress the prefixing of file names on output
-r, --recursive, read all files under a directory recursively
mvp
źródło
niesamowite! Dziękuję Ci. btw - czy wszystkie inne argumenty są niezbędne, które mam w poleceniu? a co, jeśli nie mogę tego potokować przez przypadek (na wszelki wypadek).
Tim Kamm
2
Nie sądzę, aby były one konieczne (z wyjątkiem -roczywiście), ale nie powinny boleć (nie -a
użyłbym
3
Dokładnie to, czego potrzebowałem. Mój wzorzec został znaleziony dwukrotnie w tej samej linii i grep -m 1z tego powodu zwrócił oba wystąpienia. |head -1rozwiązałem to!
harperville,
6
@Chris_Rands dokładne zachowanie zależy od powłoki, w której działasz. Head wyjdzie, gdy tylko napotka pierwszą linię. grep zakończy działanie przy następnej próbie zapisu po wyjściu z głowy. Niektóre powłoki będą czekać, aż wszystkie elementy potoku zakończą się, inne spowodują zamknięcie całej rury, gdy tylko zakończy się ostatni program w rurze.
puhlen
1
@ 3Qn, nie rozumiem Twojego komentarza: first not first from result. Ta odpowiedź drukuje pierwsze dopasowanie w dowolnym pliku i zatrzymuje się. Czego jeszcze się spodziewałeś?
mvp
31

Możesz przesyłaćgrep wyniki do headw połączeniu ze stdbuf .

Zauważ, że aby zapewnić zatrzymanie po N-tym dopasowaniu, musisz stdbufupewnić się, grepże nie buforujesz jego wyniku:

stdbuf -oL grep -rl 'pattern' * | head -n1
stdbuf -oL grep -o -a -m 1 -h -r "Pulsanti Operietur" /path/to/dir | head -n1
stdbuf -oL grep -nH -m 1 -R "django.conf.urls.defaults" * | head -n1

Gdy tylko headzużyje 1 linię, zostanie zakończona i grepotrzyma, SIGPIPEponieważ nadal wysyła coś do potoku, gdy headgo nie ma.

Zakłada się, że żadna nazwa pliku nie zawiera znaku nowej linii.

Venkat Kotra
źródło
Staram się przyjąć takie rozwiązanie, aby szukać w wielu archiwalnych plików z xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. To jednak nie kończy się przy pierwszym meczu. Jakakolwiek rada?
DKroot
1
Nie grepjest --line-bufferedopcja zapobiegają bufor napowietrznych bez wywoływania dodatkowego narzędzia?
David
23

Mój program podobny do grep-a ackma -1opcję, która zatrzymuje się przy pierwszym dopasowaniu znalezionym gdziekolwiek. Obsługuje również -m 1to, do którego odnosi się @mvp. Umieściłem go tam, ponieważ jeśli szukam dużego drzewa kodu źródłowego, aby znaleźć coś, co wiem, że istnieje tylko w jednym pliku, nie trzeba go szukać i trzeba nacisnąć Ctrl-C.

Andy Lester
źródło
więc powiedziałbyś, że potwierdzenie jest szybsze niż grep? Bardzo zależy mi również na współczynniku prędkości.
Tim Kamm,
1
ack może być szybszy niż grep, w zależności od tego, czego szukasz. Pamiętaj, że ack polega na wyszukiwaniu kodu źródłowego. Jeśli chcesz przeszukać ogólne pliki, jest to mniej dobre, przynajmniej w wersji 1.x. Przeczytaj o ack i sprawdź, czy może pasuje do twoich potrzeb.
Andy Lester,
2
Używam Ack od dłuższego czasu, ale ostatnio przełączyłem się na
Srebrnego
Uważam, że powinna to być jedyna odpowiedź, ponieważ OP powiedział, że chciałby to zrobić za pomocą grep, ale druga odpowiedź używa head (obie prace oczywiście), ale istnieją pewne środowiska osadzone / self-made z minimalnymi narzędziami, w których grep jest powszechny i ​​tail / głowa nie jest.
Areeb Soo Yasir
Warto wspomnieć, że agmoże to być szybkie, ale nie ma -1opcji przydatnej w tym przypadku
jja
3

Możesz użyć poniższego polecenia, jeśli chcesz wydrukować całą linię i nazwę pliku, jeśli wystąpienie określonego słowa w bieżącym katalogu, którego szukasz.

grep -m 1 -r "Not caching" * | head -1
Gaurav londhe
źródło
2

Pojedyncza wkładka, wykorzystująca find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit
Yam Marcovic
źródło
6
Będzie to bardzo powolne, ponieważ find odrodzi kopię grep dla każdego znalezionego pliku. grep -rdziała o wiele szybciej - to tylko jedna kopia, która wykonuje przechodzenie przez katalog.
mvp,
Prawdziwe; chociaż find można dostosować tak, aby działał tylko na filtrowanych wynikach, co może sprawić, że operacja będzie znacznie szybsza niż catch-all grep. Zależy od kontekstu.
Yam Marcovic,