Imprimer la ligne correspondante et la nième ligne à partir de la ligne correspondante

18

J'essaie d'imprimer la ligne correspondante et la 4ème ligne de la ligne correspondante (ligne contenant l'expression que je recherche).

J'utilise le code suivant: sed -n 's/^[ \t]*//; /img class=\"devil_icon/,4p' input.txt

Mais cela n'imprime que la ligne correspondante.

Cela imprime uniquement la 4ème ligne. awk 'c&&!--c;/img class=\"devil_icon/{c=4}' input.txt

Je dois imprimer à la fois la ligne correspondante et la 4e ligne uniquement.

debal
la source
Utilisation egrep "pattern" -A4
Valentin Bajrami
@ val0x00ff qui imprime aussi les lignes intermédiaires .. c'est-à-dire: il imprime les 4 lignes suivantes à partir de la ligne correspondante
debal
vous dites "J'essaie d'imprimer la ligne correspondante et la 4ème ligne de la ligne correspondante". Cela grep -A 4 "pattern" file | sed -n '4p'fait exactement ce que vous voulez, à moins que je ne vous comprenne mal
Valentin Bajrami
non ça ne marche pas. La sortie du code ci-dessus était </td>qui n'est pas la 4ème ligne
debal

Réponses:

18

En awk, vous le feriez comme suit

awk '/pattern/{nr[NR]; nr[NR+4]}; NR in nr' file > new_file`

ou

awk '/pattern/{print; nr[NR+4]; next}; NR in nr' file > new_file`

Explication

La première solution trouve toutes les lignes qui correspondent pattern. Lorsqu'il trouve une correspondance, il stocke le numéro d'enregistrement ( NR) dans le tableau nr. Il stocke également le 4ème enregistrement NRdans le même tableau. Cela se fait par le nr[NR+4]. Chaque enregistrement ( NR) est ensuite vérifié pour voir s'il est présent dans le nrtableau, si c'est le cas, l'enregistrement est imprimé.

La deuxième solution fonctionne essentiellement de la même manière, sauf lorsqu'elle rencontre la patternligne imprimée, puis stocke le 4e enregistrement devant lui dans le tableau nr, puis passe à l'enregistrement suivant. Ensuite, lorsque vous awkrencontrez ce 4ème enregistrement, le NR in nrbloc sera exécuté et imprimera cet enregistrement +4 par la suite.

Exemple

Voici un exemple de fichier de données, sample.txt.

$ cat sample.txt 
1
2
3
4 blah
5
6
7
8
9
10 blah
11
12
13
14
15
16

En utilisant la 1ère solution:

$ awk '/blah/{nr[NR]; nr[NR+4]}; NR in nr' sample.txt 
4 blah
8
10 blah
14

Utilisation de la 2ème solution:

$ awk '/blah/{print; nr[NR+4]; next}; NR in nr' sample.txt 
4 blah
8
10 blah
14
Valentin Bajrami
la source
3
Nice, +1. Vous utilisez beaucoup de awkraccourcis ici, pourriez-vous ajouter une courte explication (des choses comme l'impression étant impliquée dans awk et que les tableaux sont associatifs, etc.)?
terdon
un accord avec @terdon s'il vous plaît pourriez-vous expliquer un peu le code.
debal
@slm Merci d'avoir amélioré et fourni la réponse complète!
Valentin Bajrami
1
Merci pour la réponse, j'ai aussi appris quelque chose de nouveau.
slm
4
sed -n 's/^[ \t]*/; /img class=\"devil_icon/,+4 { 3,5d ; p }' input.txt

J'ajoute simplement une suppression des lignes appropriées, avant l'impression { 3,5d ; p }.

Drav Sloan
la source
votre expression produit une erreur: sed: -e expression #1, char 18: unknown option to s'`
minéraux
4

Vous pouvez essayer l' -Aoption avec grep, qui spécifie le nombre de lignes à imprimer après la ligne correspondante. Ajoutez ceci sedet vous obtiendrez les lignes requises.

grep -A 4 pattern input.txt | sed -e '2,4d'

En utilisant sed, nous supprimons le de la deuxième ligne jusqu'à la quatrième.

Barun
la source
3
Cela suppose une seule correspondance de patterndans le fichier.
terdon
2

Voici un moyen en Perl qui peut gérer un nombre arbitraire de lignes correspondantes:

perl -ne '/pattern/ && do{$c=$.; print}; $.==$c+4 && print' file > new_file`

En Perl. la variable spéciale $.est le numéro de ligne actuel. Ainsi, chaque fois que je trouve une ligne correspondante pattern, je l'imprime et enregistre son numéro de ligne sous $c. J'imprime ensuite à nouveau lorsque le numéro de ligne actuel est 4 de plus que celui imprimé précédemment.

terdon
la source
0
awk 'c&&!--c;/img class=\"devil_icon/{c=4};/img class=\"devil_icon/' input.txt

Vous faites essentiellement une recherche et un remplacement. Vous pouvez ajouter juste une trouvaille dans la même commande et elle imprimera les deux :)

awk 'c&&!--c;/pattern/{c=4};/pattern/' input.txt
bacoNx1000
la source