Personaggi Grep prima e dopo la partita?


144

Usando questo:

grep -A1 -B1 "test_pattern" file

produrrà una riga prima e dopo il modello corrispondente nel file. C'è un modo per visualizzare non linee ma un numero specificato di caratteri?

Le righe nel mio file sono piuttosto grandi, quindi non mi interessa stampare l'intera riga, ma osservo solo la corrispondenza nel contesto. Qualche suggerimento su come fare questo?


Risposte:


184

3 caratteri prima e 4 caratteri dopo

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and

5
Una buona risposta per piccole quantità di dati, ma inizia a rallentare quando si corrispondono> 100 caratteri, ad esempio nel mio file XML gigante, voglio {1,200} prima e dopo, ed è troppo lento da usare.
Benubird,

3
La versione awk di @amit_g è molto più veloce.
ssobczak,

6
Non disponibile su Mac OSX, quindi questa non è una soluzione ampiamente disponibile. La versione -E (elencata di seguito) è una soluzione migliore. Che cos'è -P? Continua a leggere ... -P, --perl-regexp Interpreta PATTERN come un'espressione regolare Perl (PCRE, vedi sotto). Questo è altamente sperimentale e grep -P può avvisare di funzionalità non implementate.
Xofo

2
Su OSX installare tramite: brew install homebrew/dupes/greped eseguirlo come ggrep.
Kenorb,

1
Come suggerito da @Benubird, ciò sarà senz'altro impossibile da usare per file di grandi dimensioni con un ambiente moderatamente ampio desiderato per il target della partita.
matanster

113
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

Questo abbinerà fino a 5 caratteri prima e dopo il tuo schema. L'opzione -o dice a grep di mostrare solo la corrispondenza e -E di usare un'espressione regolare estesa. Assicurati di mettere le virgolette intorno alla tua espressione, altrimenti potrebbe essere interpretato dalla shell.


1
Buona risposta, interessante che è limitato a 2 ^ 8-1 per la lunghezza nelle {} in modo da {0,255}opere {0,256}grep: invalid repetition count(s)
codemonkey

Questo sembra diventare notevolmente meno performante quando aumento il numero di caratteri corrispondenti (5 -> 25 -> 50), hai idea del perché?
Adam Hughes,

37

Puoi usare

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file

2
Funziona bene anche con file un po 'più grandi
Touko

4
come puoi usarlo per trovare più corrispondenze per riga?
koox00,

1
Qual è il significato del primo numero nelle coppie tra parentesi graffe? Come gli 0 in "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
Lew Rockwell Fan,

È molto più veloce ma non preciso come la risposta di @ ekse.
Abdollah,

24

Intendi, in questo modo:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

Che stamperà fino a venti caratteri su entrambi i lati di test_pattern. La \{0,20\}notazione è simile *, ma specifica da zero a venti ripetizioni invece di zero o più. -oDice di mostrare solo la corrispondenza stessa, piuttosto che l'intera riga.


Questo comando non funziona per me:grep: Invalid content of \{\}
Alexander Pravdin

0

Con gawk, è possibile utilizzare la funzione di corrispondenza:

    x="hey there how are you"
    echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
    ere   are

Se stai bene perl, soluzione più flessibile: in seguito verranno stampati tre caratteri prima del motivo seguito dal motivo effettivo e quindi 5 caratteri dopo il motivo.

echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
ey there how

Questo può essere applicato anche alle parole anziché ai soli caratteri. In seguito verrà stampata una parola prima della stringa di corrispondenza effettiva.

echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
hey

Di seguito verrà stampata una parola dopo il motivo:

echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
how

Di seguito verrà stampata una parola prima del motivo, quindi la parola effettiva e quindi una parola dopo il motivo:

echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
hey there how

0

Puoi usare regexp grep per trovare + second grep per evidenziare

echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string

23_string_and

inserisci qui la descrizione dell'immagine


0

Non ricorderò mai facilmente questi modificatori di comandi criptici, quindi ho preso la risposta migliore e l'ho trasformata in una funzione nel mio ~/.bashrcfile:


cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search patttern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

Ecco come appare in azione:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

Il file in questione è una linea continua da 25K ed è senza speranza trovare ciò che stai cercando usando regolarmente grep.

Nota i due diversi modi in cui puoi chiamare cgrepquel grepmetodo parallelo .

Esiste un modo "più elegante" di creare la funzione in cui "$ 2" viene passato solo quando impostato che salverebbe 4 righe di codice. Non ce l'ho a portata di mano però. Qualcosa del genere ${parm2} $parm2. Se lo trovo rivedrò la funzione e questa risposta.

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.