113 votes

Comment sélectionner des lignes entre deux motifs?

J'ai un fichier comme suit, et je voudrais imprimer les lignes et entre deux schémas PAT1 et PAT2.

1
2
PAT1
3    - first block
4
PAT2
5
6
PAT1
7    - second block
PAT2
8
9
PAT1
10    - third block

J'ai lu Comment faire pour sélectionner des lignes entre deux marqueurs modèles, qui peut se produire plusieurs fois avec awk/sed mais je suis curieux de voir toutes les combinaisons possibles de cette situation, l'impression du motif ou pas.

Comment puis-je sélectionner les lignes entre les deux modèles?

167voto

fedorqui Points 42938

Imprimer les lignes entre PAT1 et PAT2

$ awk '/PAT1/,/PAT2/' file
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block

Ou, à l'aide de variables:

awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}' file

Comment cela fonctionne?

  • /PAT1/ correspond lignes de ce texte, ainsi que d' /PAT2/ n'.
  • /PAT1/{flag=1} jeux de l' flag lorsque le texte PAT1 se trouve dans une ligne.
  • /PAT2/{flag=0} unsets l' flag lorsque le texte PAT2 se trouve dans une ligne.
  • flag est un modèle à l'action par défaut, qui est de print $0: si flag est égal à 1, la ligne est imprimée. De cette façon, il aura l'impression de toutes ces lignes du temps PAT1 se produit et jusqu'à la prochaine PAT2 est observée. Cela permettra également d'imprimer les lignes du dernier match de l' PAT1 jusqu'à la fin du fichier.

Imprimer les lignes entre PAT1 et PAT2 - non compris PAT1 et PAT2

$ awk '/PAT1/{flag=1; next} /PAT2/{flag=0} flag' file
3    - first block
4
7    - second block
10    - third block

Il utilise next de sauter de la ligne qui contient PAT1 afin d'éviter d'être imprimé.

Cet appel à l' next peut être supprimé par remaniement blocs: awk '/PAT2/{flag=0} flag; /PAT1/{flag=1}' file.

Imprimer les lignes entre PAT1 et PAT2 - y compris PAT1

$ awk '/PAT1/{flag=1} /PAT2/{flag=0} flag' file
PAT1
3    - first block
4
PAT1
7    - second block
PAT1
10    - third block

En plaçant flag à la fin, il déclenche l'action qui a été mis sur PAT1 ou PAT2: pour imprimer sur PAT1, de ne pas imprimer sur PAT2.

Imprimer les lignes entre PAT1 et PAT2 - y compris PAT2

$ awk 'flag; /PAT1/{flag=1} /PAT2/{flag=0}' file
3    - first block
4
PAT2
7    - second block
PAT2
10    - third block

En plaçant flag au tout début, il déclenche l'action qui a été défini précédemment, et donc d'imprimer la clôture motif, mais pas le début.

Imprimer les lignes entre PAT1 et PAT2 - à l'exclusion des lignes à partir de la dernière PAT1 à la fin du fichier si aucun autre PAT2 se produit

Ceci est basé sur une solution par Ed Morton.

awk 'flag{
        if (/PAT2/)
           {printf "%s", buf; flag=0; buf=""}
        else
            buf = buf $0 ORS
     }
     /PAT1/ {flag=1}' file

Comme un one-liner:

$ awk 'flag{ if (/PAT2/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /PAT1/{flag=1}' file
3    - first block
4
7    - second block

# note the lack of third block, since no other PAT2 happens after it

Cela permet de maintenir toutes les lignes sélectionnées dans un tampon qui est renseigné à partir du moment où PAT1 est trouvé. Ensuite, il continue à être rempli avec les lignes suivantes jusqu'à ce que PAT2 est trouvé. Dans ce point, il imprime le contenu stocké et vide la mémoire tampon.

98voto

hek2mgl Points 38787

Quel est le classique sed solution?

Imprimer les lignes entre PAT1 et PAT2

sed -n '/PAT1/,/PAT2/{/PAT1/!{/PAT2/!p}}' file

ou même (Merci Sundeep):

sed -n '/PAT1/,/PAT2/{//!p}'

Le ci-dessus excluent la gamme des frontières.

Imprimer les lignes entre PAT1 et PAT2 - y compris PAT1 et PAT2

Les éléments suivants devraient inclure la gamme des frontières, ce qui est encore plus simple:

sed -n '/PAT1/,/PAT2/p' file

Imprimer les lignes entre PAT1 et PAT2 - y compris PAT1

Celui-ci contient juste le début de la plage:

sed -n '/PAT1/,/PAT2/{/PAT2/!p}' file

Imprimer les lignes entre PAT1 et PAT2 - y compris PAT2

La liste suivante comprend juste la fin de la plage:

sed -n '/PAT1/,/PAT2/{/PAT1/!p}' file

13voto

James Brown Points 17362

À l'aide de grep avec PCRE (si disponible) pour imprimer des marques et des lignes entre les marqueurs:

$ grep -Pzo "(?s)(PAT1(.*?)(PAT2|\Z))" file
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block
  • -P perl-regexp, PCRE. Pas dans tous grep variantes
  • -z Traiter comme un ensemble de lignes, chaque terminée par un zéro octets au lieu d'un retour à la ligne
  • -o imprimer uniquement correspondant
  • (?s) DotAll, c'est à dire. dot trouve des retours à la ligne ainsi
  • (.*?) nongreedy trouver
  • \Z Correspond seulement à la fin de la chaîne, ou avant de saut de ligne à la fin

Imprimer les lignes entre les marqueurs à l'exclusion de marqueur de fin:

$ grep -Pzo "(?s)(PAT1(.*?)(?=(\nPAT2|\Z)))" file
PAT1
3    - first block
4
PAT1
7    - second block
PAT1
10    - third block
  • (.*?)(?=(\nPAT2|\Z)) nongreedy trouver avec anticipation pour \nPAT2 et \Z

Imprimer les lignes entre les marqueurs à l'exclusion des marqueurs:

$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(?=(\nPAT2|\Z)))" file
3    - first block
4
7    - second block
10    - third block
  • (?<=PAT1\n) positif lookbehind pour PAT1\n

Imprimer les lignes entre les marqueurs à l'exclusion de marqueur de début:

$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(PAT2|\Z))" file
3    - first block
4
PAT2
7    - second block
PAT2
10    - third block

8voto

karakfa Points 604

Voici une autre approche

Inclure les deux modèles (par défaut)

 $ awk '/PAT1/,/PAT2/' file
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block
 

Masquez les deux motifs

 $ awk '/PAT1/,/PAT2/{if(/PAT2|PAT1/) next; print}' file
3    - first block
4
7    - second block
10    - third block
 

Modèle de début de masque

 $ awk '/PAT1/,/PAT2/{if(/PAT1/) next; print}' file
3    - first block
4
PAT2
7    - second block
PAT2
10    - third block
 

Modèle d'extrémité de masque

 $ awk '/PAT1/,/PAT2/{if(/PAT2/) next; print}' file
PAT1
3    - first block
4
PAT1
7    - second block
PAT1
10    - third block
 

4voto

David C. Rankin Points 2674

Vous pouvez faire ce que vous voulez avec sed par la suppression de la normale d'impression de modèle de l'espace avec -n. Par exemple, pour inclure les modèles dans la suite que vous pouvez faire:

$ sed -n '/PAT1/,/PAT2/p' filename
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block

Pour exclure les patrons et il suffit d'imprimer ce qui est entre eux:

$ sed -n '/PAT1/,/PAT2/{/PAT1/{n};/PAT2/{d};p}' filename
3    - first block
4
7    - second block
10    - third block

Qui se décompose comme

  • sed -n '/PAT1/,/PAT2/ - localiser la gamme entre PAT1 et PAT2 et la suppression de l'impression;

  • /PAT1/{n}; - si elle correspond PAT1 déplacer n (prochaine) de la ligne;

  • /PAT2/{d}; - si elle correspond PAT2 supprimer la ligne;

  • p - imprimer toutes les lignes qui relèvent /PAT1/,/PAT2/ et n'ont pas été ignorés ou supprimés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X