Perché 'grep -q' utilizza l'intero file di input?


23

Considera il seguente file di input:

1
2
3
4

In esecuzione

{ grep -q 2; cat; } < infile

non stampa nulla. Mi aspetto che stampi

3
4

Posso ottenere l'output previsto se lo cambio in

{ sed -n 2q; cat; } < infile

Perché il primo comando non stampa l'output previsto?
È un file di input ricercabile e secondo lo standard in OPZIONI :

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

e più in basso, in USO DELL'APPLICAZIONE (sottolineare il mio):

L' -qopzione fornisce un mezzo per determinare facilmente se esiste o meno un modello (o una stringa) in un gruppo di file. Durante la ricerca di più file, fornisce un miglioramento delle prestazioni ( perché può uscire non appena trova la prima corrispondenza ) [...]

Ora, per lo stesso standard (in Introduzione , sotto INPUT FILES )

Quando un'utilità standard legge un file di input ricercabile e termina senza errori prima che raggiunga la fine del file, l'utilità deve assicurarsi che l'offset del file nella descrizione del file aperto sia posizionato correttamente dopo l'ultimo byte elaborato dall'utilità [. ..]

tail -n +2 file
(sed -n 1q; cat) < file
...

Il secondo comando è equivalente al primo solo quando il file è ricercabile.


Perché grep -qconsuma l'intero file?


Questo è gnu grepimportante (anche se Kusalananda ha appena confermato che lo stesso accade su OpenBSD)


OpenBSD grepè un fork di qualcosa chiamato FreeGrep , se qualcuno si chiede.
Kusalananda

Risposte:


37

grep si ferma presto, ma bufferizza il suo input, quindi il tuo test è troppo breve (e sì, mi rendo conto che il mio test è imperfetto poiché non è cercabile):

seq 1 10000 | (grep -q 2; cat)

inizia a 6776 sul mio sistema. Che corrisponde al 32KiB BUFFER utilizzato per impostazione predefinita in GNU grep:

seq 1 6775 | wc

uscite

   6775    6775   32768

Si noti che POSIX menziona solo miglioramenti delle prestazioni

Durante la ricerca di più file

Ciò non crea aspettative per i miglioramenti delle prestazioni dovuti alla lettura parziale di un singolo file.


2

Ciò è ovviamente dovuto al buffering che grepaccelera le cose. Ci sono strumenti che sono specificamente progettati per leggere tutti i caratteri richiesti e non di più. Uno di questi è expect:

{ expect -c "log_user 0; expect 2"; cat; } < infile

Non ho un sistema per provare questo, ma credo expectche divorerà tutto fino a quando non incontra la stringa prevista ( 2), e quindi termina, lasciando il resto dell'input per cat.


1

Stai confondendo sed e grep.

Per il comando sed, -2qsta dicendo di uscire dall'iterazione corrente se alla seconda riga, l' -nopzione sta dicendo di funzionare in modo silenzioso, quindi otterrai tutte le righe dopo la seconda.

Il comando grep viene eseguito per impostazione predefinita per generare tutte le righe corrispondenti, ma l' -qopzione dice di non produrre nulla su stdout. quindi, se l'ingresso contiene un "2" avrà un valore di uscita di SUCCESS, altrimenti FAILURE. Cosa sono dipende dal sistema operativo e dalla shell. Quindi, in genere si direbbe se una riga corrisponde esaminando il valore di uscita del processo grep. Ciò è utile in una pipeline in cui si desidera sapere se l'input contiene un valore come test. Per esempio

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

In questo caso non ci interessa davvero vedere tutte le linee corrispondenti, ci importa solo se ne esiste almeno una. Il report_crash_via_emailprocesso / funzione potrebbe quindi spegnersi e riaprire il file oppure no.

Se vuoi che il tuo processo grep si fermi dopo aver trovato il carattere "2" - non lo farà per impostazione predefinita, controllerà ogni linea cercando di vedere se corrisponde - devi dirgli di farlo. L'opzione della riga di comando è quella -m <value>. Quindi per il tuo caso grep -q -m1 2,.


6
La tua risposta è un'informazione utile per l'uso generale di, grepma questa domanda è chiedere qualcosa di più sottile ed esoterico. Sembra che tu abbia letto la domanda troppo rapidamente per capire il comportamento reale da interrogare. Inoltre, GNU grep non interrompere la ricerca quando viene utilizzato con -q(come consentito nella citazione da specifiche POSIX): La pagina man per GNU grep afferma che “Exit [S] immediatamente con lo stato zero se una partita è stato ritrovato” . FWIW, ho modificato la tua domanda per mostrare come puoi formattare i post futuri. Benvenuto a Stack Exchange .
Anthony G - giustizia per Monica il

Detto questo, la risposta di @ user212377 è corretta: in questo caso grepviene chiesto se nel file esiste "2", niente di più e niente di meno. Non si comporta come sede consuma record fino a quel momento e lascia il resto per ulteriori elaborazioni. Legge fino a quando non sa che c'è un '2' o che non lo è, chiude il file e restituisce il risultato.
Keith Davies il

grepinfatti 'consuma l'intero file' (ignorando le considerazioni sul buffering) se la stringa di ricerca non è presente nel file (il che è provabile solo esaminando l'intero file). Nulla di meno, la lettura del file si interrompe , il file viene chiuso e SUCCESS restituito.
Keith Davies il
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.