Mostra tutti i file fino alla partita


71

grep --before-context 5 mostra 5 righe prima della partita.

Voglio mostrare tutto prima della partita.
Fare grep --before-context 99999999funzionerebbe ma non è molto ... professionale.

Come mostrare tutti i file fino alla partita?

Risposte:


95

Sed è meglio per questo.

Basta fare:

sed '/PATTERN/q' FILE

Funziona così:

Per ogni riga, osserviamo se corrisponde /PATTERN:

  • se sì, lo stampiamo e usciamo
  • altrimenti, lo stampiamo

Questa è la soluzione più efficiente, perché appena vede PATTERNsi chiude. Senza q, sed continuerebbe a leggere il resto del file e non farebbe nulla con esso. Per file di grandi dimensioni può fare la differenza.

Questo trucco può anche essere usato per emulare head:

sed 10q FILE

Appena provato, emette solo la prima riga del file ... anche se la corrispondenza è alla riga 38.
Nicolas Raoul

Funziona bene per me. Puoi fare un esempio di input e output effettivi? E il comando che stai eseguendo così com'è.
Mikel,

Avevo provato il tuo comando prima di modificarlo, era: sed '/ PATTERN / p; q' FILE
Nicolas Raoul

7
Cosa devo fare se non voglio stampare la linea con la corrispondenza del motivo?
tommy.carstensen,

4
@ tommy.carstensen: sed '/PATTERN/Q' FILEsalterà la linea corrispondente. Qè un'estensione GNU, quindi non funzionerà con nessun sed.
Alex O

37

sed può sostituire la maggior parte delle funzionalità di grep.

sed -n '1,/<pattern>/ p' <file>

Questo significa stampare dalla prima riga fino a quando il motivo non viene abbinato.

Un paio di esempi di gamma

sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2

3
Questo comando è buono, ma puoi fare di meglio. In questo modo legge l'intero file, ma è possibile uscire non appena ha trovato una corrispondenza.
Mikel,

3
Cosa devo fare se non voglio stampare la linea con la corrispondenza del motivo?
tommy.carstensen,

34

stampa fino alla partita inclusa:

awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename

stampa fino a MA NON compresa la corrispondenza:

awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename

11
QE 'bello ma specifico per gli gnu, sed -n '/pattern/!p;//q'sarebbe più portatile.
don_crissti,

@don_crissti: dovresti farne una risposta, penso che sia una buona risposta (: sono un po 'curioso di come funzioni, però. Credo !che pvalga per le linee che non corrispondono pattern, ma poi //qmi confonde ...
jwd

2
@don_crissti: ah, l'ho capito - //significa "espressione regolare precedente" (ho pensato che significasse "corrisponde alla stringa vuota"). Penso che una versione più breve della stessa soluzione sia sed -n '/pattern/q;p:?
jwd

@jwd - anzi, è più breve. 👍
don_crissti il

1

I seguenti grepmetodi GNU puri non sono efficienti.

Cerca tutto fino alla prima istanza della stringa " pippo " nella barra dei file , usando tre greps:

grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar

Corrispondenza fino all'ultima istanza di " pippo ":

grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar

Nota: i dettagli sull'ultimo grepsono disponibili in: Regex (grep) per la ricerca su più righe necessaria .


Perché mai si vorrebbe usare 7 greps (+ pcre) quando si tratta semplicemente di eseguire una singola sedchiamata: sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'??
don_crissti,

@don_crissti, il tuo sedcodice sembra valere la sua risposta o potrebbe essere aggiunto a uno degli altri. Ri 7 greps: Perché non c'era una greprisposta ... (in più, la risposta aiuta a mostrare perché no.)
agc

Non è il mio codice, basta fare clic su di esso ... Anche se quello era il mio codice non risponde alla Q qui, quindi non lo pubblicherei come risposta.
don_crissti,

1

Aggiungendo alla risposta di Mikel sopra ...


Per stampare tutte le righe fino a, ma non includere , la prima riga in FILEcontenimento PATTERN, provare:

  • sed '/.*PATTERN.*/{s///;q;}' FILE

Questo corrisponde all'intera riga contenente il modello, lo sostituisce con una riga vuota, quindi si chiude senza elaborare il resto del file.


Post-script:

Il modo più semplice / chiaro a cui potevo pensare per evitare di stampare una nuova riga alla fine (senza coinvolgere un altro strumento), era di eseguire di nuovo sed ed eliminare la nuova riga finale:

sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'

... e dal momento che stiamo eliminando comunque quella linea, il nostro lavoro precedente è ridondante e possiamo semplificare per:

sed '/PATTERN/q' FILE | sed '$d'

La risposta di Glenn - e il mio commento lì - mostrano come farlo con un'unica sedinvocazione.
don_crissti,

(Grazie per questo - ho visto il tuo commento sulla risposta di AGC ma o ho perso l'altro o lo ho sfiorato solo perché il mio cervello non ama i doppi negativi.) Dato che stavo usando questo sia in a tcshche in bashalias, dovevo assicurarmi di aveva una soluzione a una riga relativamente concisa che funzionava sia in standard che GNU sed(per portabilità); tutti i requisiti che il tuo contributo potrebbe aver soddisfatto. Come qualcuno che usa sed molto raramente, il mio requisito più importante era qualcosa che potevo capire rapidamente quando volevo modificarlo o riutilizzarlo facilmente tra anni.
Jim Grisham,

1

Per le persone che scelgono di ricordare solo gli strumenti di base nel lavoro quotidiano e disposti ad accettare soluzioni meno eleganti e meno efficienti:

head -n $(grep -n pattern filename | cut -d: -f1) filename

Se questo comando è per uno script, cercherò soluzioni più eleganti (e possibilmente efficienti). Se questo è un comando una tantum o uno script usa e getta, non mi interessa.


1
Bella idea, ma tre comandi quando uno lo farà.
Mikel,

1
Conoscere le basi è davvero molto buono. Tuttavia, è meglio conoscere lo strumento giusto per il lavoro.
soulmerge,

Se questo comando è per uno script, cercherò soluzioni più eleganti (e possibilmente efficienti). Se questo è un comando una tantum (o uno script usa e getta), non mi interessa.
lesmana,

0

È inoltre possibile utilizzare uno dei seguenti

tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac 

o

tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac

o

tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac

La prima opzione è molto simile a quella suggerita dall'OP, ma assicura che ti mostri abbastanza righe prima del contesto contando le righe nel file

La seconda opzione cerca il numero di riga della prima corrispondenza (puoi cambiarlo anche cambiando la 'testa' interna) e quindi usa la testa su quel numero

L'ultima opzione sostituisce tutte le nuove linee con la corrispondenza e quindi sostituisce due partite adiacenti con una nuova linea. L'output di questo è una riga per ogni blocco di testo tra due corrispondenze. Dopodiché usa 'head' per scegliere la prima riga (che comprende il blocco di testo fino alla prima corrispondenza) e che ritrasforma ogni corrispondenza in una nuova riga. questa opzione funziona solo se il file è nel seguente formato

pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern 
texttexttext
texttexttexttexttexttexttexttexttext

e così via


2
considera di spiegare come funzionano, specialmente perché quel sedcomando in fondo è un po 'nodoso.
Strugee,

la prima opzione è molto simile a ciò che l'OP ha suggerito solo che si assicura che mostri abbastanza kines prima del contesto contando le linee nel filr,
user122778
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.