grep per restituire l'ennesima riga prima e dopo l'incontro


12

So che con grep posso usare i campi -Ae -Btirare le righe precedenti e successive da una partita.

Tuttavia, inseriscono tutte le righe tra le corrispondenze in base a quante righe sono state specificate.

grep -r -i -B 5 -A 5 "match" 

Vorrei ricevere solo la 5a linea prima di una partita e la 5a linea dopo la partita oltre alla linea abbinata e non ottenere le linee tra.

C'è un modo per farlo con il grep?


1
Puoi farlo collegandolo a sed. Ho appena provato questo e ha funzionato, ma ha funzionato solo quando c'era una corrispondenza esatta nel file: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
Terrance

@Terrance grazie per il suggerimento, come dici tu, dato che sto collezionando migliaia di righe, questo non funzionerà.
Chollida,

Non credo che grep funzionerà da solo ... Sto lavorando a uno script bash per te
Joshua Besneatte,

Nessun problema! Un po 'interessato a vedere quali risposte ottieni. =)
Terrance

è presente in un file o in più file?
Joshua Besneatte,

Risposte:


1

Lo strumento che si desidera utilizzare si chiama setaccio. Questo è fondamentalmente un grep con gli steroidi. Grep in parallelo. Sift ha un'enorme quantità di opzioni per fare esattamente quello che vuoi, in particolare per restituire una particolare riga rispetto a una corrispondenza (e) che può / potrebbe non essere seguita / preceduta da un testo.

Mi stupisce che vagliare non sia lo gnu mainstream in quanto è stato scritto nella lingua go ma si installa su Linux bene. Le ricerche IT in parallelo utilizzano tutte le cpus di enormi quantità di testo in cui grep richiede solo settimane per fare lo stesso.

Setaccia sito Web - vedi esempi


Benvenuto in AskUbuntu, grazie per la risposta. È necessario fornire un esempio CLI in grado di risolvere questo problema specifico anziché fornire un collegamento al setaccio del sito Web. Dopotutto, questa è una domanda e risposta.
Bernard Wei,

12

Se:

cat file
a
b
c
d
e
f match
g
h
i match
j
k
l
m
n
o

Poi:

awk '
    {line[NR] = $0} 
    /match/ {matched[NR]} 
    END {
        for (nr in matched)
            for (n=nr-5; n<=nr+5; n+=5) 
                print line[n]
    }
' file
a
f match
k
d
i match
n

+1, ma potresti spiegare la semantica di /match/ {matched[NR]}? Non ho mai visto un array o una variabile come un intero comando. Mette il numero di record corrente di ogni linea abbinata nell'array?
Joe

Questa è una strana stranezza: se fai riferimento a un elemento array senza assegnazione, quella chiave viene aggiunta all'array (senza un valore). Quindi quella chiave appare nell'espressione key in array. Quello che sto facendo è ricordare i numeri di riga in cui appare lo schema
Glenn Jackman

6

Questa è sostanzialmente la soluzione di Glenn, ma implementata con Bash, Grep e sed.

grep -n match file |
    while IFS=: read nr _; do
        sed -ns "$((nr-5))p; $((nr))p; $((nr+5))p" file
    done

Si noti che i numeri di riga inferiori a 1 comporteranno l'errore sed e che i numeri di riga maggiori del numero di righe nel file non lo faranno stampare.

Questo è solo il minimo indispensabile. Per farlo funzionare in modo ricorsivo e gestire il numero di riga sopra i casi richiederebbe qualcosa.


6

Non si può fare solo con grep. Se edè un'opzione:

ed -s file << 'EOF' 
g/match/-5p\
+5p\
+5p
EOF  

Lo script dice sostanzialmente: per ogni corrispondenza di / match /, stampa la riga 5 righe prima, quindi 5 righe dopo, quindi 5 righe dopo.


5
@ubashu Pensi che sarà più utile all'OP dare un semplice flat "non si può fare con grep"? Sto fornendo quella che credo sia una buona alternativa per risolvere il problema di OP. Dal Centro assistenza: "Qual è, in particolare, la domanda che ti viene posta? Assicurati che la tua risposta lo fornisca o un'alternativa praticabile. La risposta può essere" non farlo ", ma dovrebbe includere anche" prova questo " ".
JoL

edè sempre una risposta, perché edè l'editor di testo standard.
dessert

5
@ubashu Sebbene non sia una greprisposta, la risposta di "Non puoi farlo con X, ma puoi farlo con Y, ecco come" è ancora una risposta valida poiché non solo rispondi alla domanda di OP ma fornisci anche un'alternativa avrebbe funzionato. Questo è un tipo valido di risposta qui.
Thomas Ward

5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

Qui stiamo usando la funzione di awk per chiamare il comando esterno per stampare le linee che awk ha abbinato al modellosystem(command)sedmatch con la 5a linea prima e dopo la corrispondenza.

La sintassi è semplice, devi solo inserire il comando esterno stesso tra virgolette doppie e i suoi interruttori e sfuggire alle cose che vuoi esattamente passare al comando, tutto il resto relativo alle awkopzioni stesse dovrebbe essere al di fuori delle virgolette. Quindi la sed di seguito :

"sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME

tradurre in:

sed -n "NR-5p; NRp; NR+5p" FILENAME

NRè il numero di riga corrispondente al modello matched FILENAMEè il nome del file di elaborazione corrente che passa awk.


2

usando il file di testo di esempio di @ glenn e usando perl invece di awk:

$ perl -n0E 'say /(.*\n)(?=(?:.*\n){4}(.*match.*\n)(?:.*\n){4}(.*\n))/g' ex

darà gli stessi risultati, ma corre più veloce:

a
f match
k
d
i match
n

João, ti stai presentando nella coda di revisione di LQ e @waltinator ha votato per l'eliminazione, quindi la prossima volta diventa un po ' più prolisso ... ;-) Anche +1 per farti uscire dalla coda di LQ ... : P
Fabby,

1
@JJoao Coda di recensioni di bassa qualità. La tua risposta probabilmente è stata raccolta lì perché era il 90% di codice.
wjandrea,

1
@JJoao Il 90% è solo il mio modo di spiegarlo. Non so quali euristiche vengano effettivamente utilizzate.
wjandrea,

1
Menos café, mais escrita! @JJoao : D ;-): D
Fabby,

1
@Fabby: Sem café nada funciona: D - probabilmente verrebbe visualizzato nella LCQ (= coda di caffè bassa)
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.