grep pour renvoyer les Nième et Mième lignes avant et après le match

12

Je sais qu'avec grep je peux utiliser les champs -Aet -Bextraire les lignes précédentes et suivantes d'une correspondance.

Cependant, ils tirent toutes les lignes entre le match en fonction du nombre de lignes spécifié.

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

Je souhaite recevoir uniquement la 5ème ligne avant un match et la 5ème ligne après le match en plus de la ligne correspondante et ne pas séparer les lignes.

Existe-t-il un moyen de le faire avec le grep?

chollida
la source
1
Vous pouvez le faire en l'insérant dans sed. Je viens de tester cela et cela a fonctionné, mais cela n'a fonctionné que lorsqu'il y avait 1 correspondance exacte dans le fichier: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
Terrance
@Terrance merci pour la suggestion, comme vous le mentionnez, car je collecte des milliers de lignes, cela ne fonctionnera pas.
chollida
Je ne pense pas que grep fonctionnera de lui-même ... Je travaille sur un script bash pour vous
Joshua Besneatte
Aucun problème! Un peu intéressé de voir quelles réponses vous obtenez. =)
Terrance
est-ce dans un fichier ou dans plusieurs fichiers?
Joshua Besneatte

Réponses:

1

L'outil que vous souhaitez utiliser s'appelle tamiser. Il s'agit essentiellement d'un grep sur les stéroïdes. Grep en parallèle. Sift a une énorme quantité d'options pour faire exactement ce que vous voulez - spécifiquement pour renvoyer une ligne particulière par rapport à une correspondance qui peut / peut ne pas être suivie / précédée d'un texte.

Cela m'étonne que sift ne soit pas un gnu traditionnel car il a été écrit dans la langue go mais s'installe très bien sur Linux. Le service informatique recherche en parallèle en utilisant toutes les énormes quantités de texte des processeurs, où grep ne prend que des semaines pour faire de même.

Site Web de Sift - voir des exemples

Brandon Haberfeld
la source
Bienvenue à AskUbuntu, merci d'avoir répondu. Vous devez fournir un exemple CLI qui peut résoudre ce problème spécifique plutôt que de fournir un lien vers le site Web de tri. Ceci est un Q&A après tout, merci.
Bernard Wei
12

Si:

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

Puis:

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
glenn jackman
la source
+1, mais pourriez-vous expliquer la sémantique de /match/ {matched[NR]}? Je n'ai jamais vu un tableau ou une variable comme une commande entière. Est-ce mettre le numéro d'enregistrement actuel de chaque ligne correspondante dans le tableau.
Joe
C'est une bizarrerie: si vous référencez un élément de tableau sans affectation, cette clé est ajoutée au tableau (sans valeur). Ensuite, cette clé apparaît dans l'expression key in array. Ce que je fais, c'est me souvenir des numéros de ligne où le motif apparaît
glenn jackman
6

Il s'agit essentiellement de la solution de Glenn, mais implémentée avec Bash, Grep et sed.

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

Notez que les numéros de ligne inférieurs à 1 entraîneront une erreur sed et que les numéros de ligne supérieurs au nombre de lignes du fichier ne l'imprimeront pas.

C'est juste le strict minimum. Pour le faire fonctionner récursivement et gérer les cas de numéro de ligne ci-dessus, il faudrait un peu de travail.

wjandrea
la source
6

Cela ne peut pas être fait avec seulement grep. Si c'est edune option:

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

Le script dit essentiellement: pour chaque correspondance de / match /, imprimez la ligne 5 lignes avant cela, puis 5 lignes après cela, puis 5 lignes après cela.

JoL
la source
5
@ubashu Pensez-vous que ce sera plus utile au PO de donner un simple plat "ça ne peut pas être fait avec grep"? Je fournis ce que je pense être une bonne alternative pour résoudre le problème d'OP. Depuis le centre d'aide: "Que demande précisément la question? Assurez-vous que votre réponse le propose - ou une alternative viable. La réponse peut être" ne faites pas cela ", mais elle devrait également inclure" essayez ceci à la place ". . "
JoL
edest toujours une réponse, car edest l'éditeur de texte standard.
dessert
5
@ubashu Bien que ce ne soit pas une grepréponse, la réponse "Vous ne pouvez pas le faire avec X, mais vous pouvez le faire avec Y, voici comment" est toujours une réponse valide car non seulement vous répondez à la question d'OP mais vous fournissez également une alternative Ça marcherait. C'est un type de réponse valide ici.
Thomas Ward
5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

Ici, nous utilisons la fonction awk pour appeler une commande externe pour imprimer les lignes qui correspondent à awk avec le motif avec les 5 ème lignes avant et après la correspondance.system(command)sedmatch

La syntaxe est facile, il vous suffit de mettre la commande externe elle-même dans les guillemets doubles ainsi que ses commutateurs et d'échapper les choses que vous voulez exactement passer à la commande, tout le reste lié aux awkoptions lui - même devrait être en dehors des guillemets. Donc, le sed ci-dessous :

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

se traduire par:

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

NRest le numéro de ligne correspondant au modèle matchet FILENAMEle nom du fichier de traitement en cours qui passe awk.

αғsнιη
la source
2

en utilisant l'exemple de fichier texte de @ glenn et en utilisant perl au lieu de awk:

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

donnera les mêmes résultats, mais en cours d'exécution plus rapide:

a
f match
k
d
i match
n
Fabby
la source
João, vous vous présentez dans la file d'attente de révision LQ et @waltinator a voté pour la suppression, alors la prochaine fois soyez un peu plus verbeux ... ;-) Aussi +1 pour vous sortir de la file d'attente LQ ... : P
Fabby
1
@JJoao File d'attente d'examen de faible qualité. Votre réponse a probablement été récupérée car il s'agissait d'un code à 90%.
wjandrea
1
@JJoao Le chiffre de 90% est juste ma façon de l'expliquer. Je ne sais pas quelles heuristiques sont réellement utilisées.
wjandrea
1
Menos café, mais escrita! @JJoao : D ;-): D
Fabby
1
@Fabby: Sem café nada funciona: D - il apparaîtrait probablement dans la LCQ (= file d'attente de café basse)