Grep solo la prima partita e stop


329

Sto cercando una directory ricorsivamente usando grep con i seguenti argomenti sperando di restituire solo la prima corrispondenza. Sfortunatamente, ne restituisce più di uno - in effetti due l'ultima volta che ho guardato. Sembra che io abbia troppi argomenti, soprattutto senza ottenere il risultato desiderato. : - /

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

ritorna:

Pulsanti Operietur
Pulsanti Operietur

Forse grep non è il modo migliore per farlo? Dimmelo, grazie mille.

Risposte:


512

-m 1significa restituire la prima corrispondenza in un determinato file. Ma continuerà comunque a cercare in altri file. Inoltre, se ci sono due o più abbinati nella stessa riga, verranno visualizzati tutti.

È possibile utilizzare head -1per risolvere questo problema:

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

spiegazione di ciascuna opzione 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

eccezionale! grazie. btw - sono necessari tutti quegli altri argomenti che ho nel comando? e se non riuscissi a convogliarlo per caso (per ogni evenienza).
Tim Kamm,

2
Non penso che siano necessari (tranne -rovviamente), ma non dovrebbero far male (non lo -a
userei

3
Esattamente quello di cui avevo bisogno. Il mio modello è stato trovato due volte sulla stessa riga e ha grep -m 1restituito entrambe le istanze per questo motivo. |head -1risolto!
Harperville,

6
@Chris_Rands il comportamento esatto dipende dalla shell in cui si sta eseguendo. Head uscirà non appena incontra la prima riga. grep uscirà la prossima volta che tenterà di scrivere dopo l'uscita di head. Alcune shell attenderanno il completamento di tutti gli elementi di una pipeline, altre causeranno l'arresto dell'intero pipe non appena termina l'ultimo programma nel pipe.
puhlen,

1
@ 3QN, non capisco il tuo commento: first not first from result. Questa risposta stampa la prima corrispondenza in qualsiasi file e si interrompe. Cos'altro ti aspettavi?
mvp,

31

È possibile reindirizzare il greprisultato headinsieme a stdbuf .

Si noti che per garantire l'arresto dopo l'ennesima corrispondenza, è necessario utilizzare stdbufper assicurarsi di grepnon bufferizzare il suo output:

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

Non appena headconsuma 1 riga, è terminato e greplo riceverà SIGPIPEperché è ancora in uscita qualcosa da pipe mentre non headc'era più.

Ciò presupponeva che nessun nome di file contenga newline.


Sto cercando di adottare questa soluzione per la ricerca in un gran numero di file di archivio con xargs: find . -name '*.gz' | xargs -I '{}' stdbuf -oL zgrep -al 'pattern' {} | head -n 1. Questo, tuttavia, non termina alla prima partita. Qualche consiglio?
DKroot,

1
Non sarebbe grep's --line-bufferedopzione Impedisci tampone in testa senza chiamare un programma di utilità supplementare?
David

23

Il mio programma grep-a-like ackha -1un'opzione che si ferma alla prima partita trovata ovunque. Supporta anche il -m 1riferimento a @mvp. L'ho inserito perché se sto cercando un grande albero di codice sorgente per trovare qualcosa che so esiste in un solo file, non è necessario trovarlo e deve premere Ctrl-C.


quindi diresti che ack è più veloce di grep? Mi preoccupo molto anche del fattore velocità.
Tim Kamm,

1
ack può essere più veloce di grep, a seconda di cosa stai cercando. Si noti che ack riguarda la ricerca del codice sorgente. Se stai cercando di cercare file generici, è meno bravo a farlo, almeno in ack 1.x. Vai a leggere su ack e vedi se forse soddisfa le tue esigenze.
Andy Lester,

2
Sto usando Ack da molto tempo ma recentemente sono passato a The Silver Searcher, che trovo più veloce in Ack
guy.gc

Credo che questa dovrebbe essere l'unica risposta perché l'OP ha affermato di volerlo fare con grep, ma l'altra risposta usa head (entrambi ovviamente lavoro) ma ci sono alcuni ambienti embedded / auto-creati con strumenti minimi in cui grep è comune e tail / la testa non lo è.
Areeb Soo Yasir,

Vale la pena ricordare che agpotrebbe essere veloce, ma non ha l' -1opzione che è utile in questo caso
jja

4

È possibile utilizzare il comando seguente se si desidera stampare l'intera riga e il nome del file se si verifica la presenza di una parola particolare nella directory corrente.

grep -m 1 -r "Not caching" * | head -1

2

Un singolo liner, usando find:

find -type f -exec grep -lm1 "PATTERN" {} \; -a -quit

6
Questo sarà molto lento, poiché find genererà una copia di grep per ogni file trovato. grep -rfunziona molto più velocemente: è una sola copia che esegue gli attraversamenti di directory.
mvp

Vero; sebbene find possa essere personalizzato per operare solo su risultati filtrati, il che può quindi rendere l'operazione molto più veloce di un grep catch-all. Dipende dal contesto.
Yam Marcovic
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.