Caractères Grep avant et après le match?

144

En utilisant ceci:

grep -A1 -B1 "test_pattern" file

produira une ligne avant et après le motif correspondant dans le fichier. Existe-t-il un moyen d'afficher non pas des lignes mais un nombre spécifié de caractères?

Les lignes de mon fichier sont assez grandes, donc je ne suis pas intéressé par l'impression de la ligne entière, mais plutôt par l'observation de la correspondance dans son contexte. Des suggestions sur la façon de procéder?

Légende
la source
1
Duplicate of unix.stackexchange.com/q/163726 Presque duplicate of stackoverflow.com/q/2034799
sondra.kinsey

Réponses:

184

3 caractères avant et 4 caractères après

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and
ДМИТРИЙ МАЛИКОВ
la source
5
Une bonne réponse pour de petites quantités de données, mais cela commence à devenir lent lorsque vous faites correspondre> 100 caractères - par exemple dans mon fichier xml géant, je veux {1 200} avant et après, et il est trop lent à utiliser.
Benubird
3
La version awk de @amit_g est beaucoup plus rapide.
ssobczak
6
Non disponible sur Mac OSX, ce n'est donc pas une solution largement disponible. La version -E (listée ci-dessous) est une meilleure solution. Qu'est-ce que -P? Lire la suite ... -P, --perl-regexp Interpréter PATTERN comme une expression régulière Perl (PCRE, voir ci-dessous). Ceci est hautement expérimental et grep -P peut avertir des fonctionnalités non implémentées.
Xofo
2
Sur OSX, installez via: brew install homebrew/dupes/grepet exécutez-le en tant que ggrep.
kenorb
1
Comme l'indique @Benubird, cela sera impossible à utiliser en termes de performances pour des fichiers volumineux avec un environnement modérément large souhaité pour la cible de correspondance.
matanster le
113
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

Cela correspondra à jusqu'à 5 caractères avant et après votre modèle. Le commutateur -o indique à grep de n'afficher que la correspondance et -E d'utiliser une expression régulière étendue. Assurez-vous de mettre les guillemets autour de votre expression, sinon elle pourrait être interprétée par le shell.

ekse
la source
1
Bonne réponse, intéressant qu'il soit plafonné à 2 ^ 8-1 pour la longueur dans le {} donc ça {0,255}marche {0,256}donnegrep: invalid repetition count(s)
CodeMonkey
Cela semble devenir considérablement moins performant à mesure que j'augmente le nombre de caractères correspondants (5 -> 25 -> 50), une idée pourquoi?
Adam Hughes le
37

Vous pourriez utiliser

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file
amit_g
la source
2
Fonctionne bien même avec des fichiers un peu plus gros aussi
Touko
4
comment pouvez-vous utiliser cela pour trouver plusieurs correspondances par ligne?
koox00 le
1
Quelle est la signification du premier nombre dans les paires entre crochets? Comme les 0 dans "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
Lew Rockwell Fan
C'est vraiment plus rapide mais pas aussi précis que la réponse de @ ekse.
Abdollah
24

Tu veux dire comme cela:

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

?

Cela imprimera jusqu'à vingt caractères de chaque côté de test_pattern. La \{0,20\}notation est similaire *, mais spécifie de zéro à vingt répétitions au lieu de zéro ou plus. Elle -oindique de n'afficher que la correspondance elle-même, plutôt que la ligne entière.

Ruakh
la source
Cette commande ne fonctionne pas pour moi:grep: Invalid content of \{\}
Alexander Pravdin
0

Avec gawk, vous pouvez utiliser la fonction de correspondance:

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

Si vous êtes d'accord avec perlune solution plus flexible: ce qui suit imprimera trois caractères avant le motif suivi du motif réel, puis 5 caractères après le motif.

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

Cela peut également être appliqué à des mots au lieu de seulement des caractères. La suite imprimera un mot avant la chaîne correspondante.

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

Ce qui suit imprimera un mot après le motif:

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

Ce qui suit imprimera un mot avant le motif, puis le mot réel, puis un mot après le motif:

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

Vous pouvez utiliser regexp grep pour trouver + second grep pour surligner

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

23_string_and

entrez la description de l'image ici

Andrew Zhilin
la source
0

Je ne me souviendrai jamais facilement de ces modificateurs de commandes cryptiques, alors j'ai pris la réponse principale et l' ai transformée en une fonction dans mon ~/.bashrcfichier:


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()

Voici à quoi cela ressemble en action:

$ 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

Le fichier en question est une ligne continue de 25K et il est impossible de trouver ce que vous recherchez en utilisant regular grep.

Notez les deux manières différentes d'appeler cgrepcette grepméthode parallèles .

Il existe une manière plus "nift" de créer la fonction où "$ 2" n'est passé que lorsqu'il est défini, ce qui permettrait d'économiser 4 lignes de code. Je ne l'ai pas sous la main. Quelque chose comme ${parm2} $parm2. Si je le trouve, je réviserai la fonction et cette réponse.

WinEunuuchs2Unix
la source