Comment sélectionner la première occurrence entre deux modèles, y compris les

27

Comment puis-je sélectionner la première occurrence entre deux modèles, y compris les. Utiliser de préférence sedou awk.

J'ai:

text
something P1 something
content1
content2
something P2 something
text
something P1 something
content3
content4
something P2 something
text

Je veux la première occurrence des lignes entre P1 et P2 (y compris la ligne P1 et la ligne P2):

something P1 something
content1
content2
something P2 something
kofucii
la source

Réponses:

22
sed '/P1/,/P2/!d;/P2/q'

... ferait le travail de manière portable en dsupprimant toutes les lignes qui ne !tombent pas dans la plage, puis en qsortant la première fois qu'il rencontre la fin de la plage. Il n'échoue pas pour P2 précédant P1, et il ne nécessite pas de syntaxe spécifique à GNU pour écrire simplement.

mikeserv
la source
Excellent! Beaucoup mieux que le mien.
muru
1
@muru - Il est souvent plus facile d'éviter les contorsions si vous essayez de cibler l'impression automatique - laissez le cycle fonctionner pour vous. C'est l'habitude dans laquelle je suis tombé de toute façon. Je pense qu'il est probablement mieux décrit comme un pruneau vs une méthode de sélection - j'ai tendance à nier un modèle plutôt que de le rechercher.
mikeserv
Cela se bloquera lors du traitement d'un fichier de grande taille.
Brain90
@ Brain90 - ne devrait pas. si vous pouvez reproduire votre plainte de manière fiable, vous devez vous adresser au responsable de votre sed... c'est un bug dans votre sedfonctionnement, et non dans le script ci-dessus.
mikeserv
1
@mikeserv Je ne l'aurais pas dit si je ne l'avais pas été. Votre inquiétude quant à savoir si je me soucie de quelques personnages est bizarre: j'ai observé que l'expression sed fonctionnait à la fois avec et sans /P2/qsur mon système; c'est ça. J'étais curieux de savoir quelque chose et je voulais partager ce que j'ai trouvé.
Alexej Magura
8

avec awk

awk '/P1/{a=1};a;/P2/{exit}' file
something P1 something
content1
content2
something P2 something
iruvar
la source
8

Dans sed:

sed -n '/P1/,/P2/p; /P2/q'
  • -nsupprime l'impression par défaut et vous imprimez des lignes entre les plages d'adresses correspondantes à l'aide de la pcommande.
  • Normalement, cela correspondrait aux deux sections, donc vous quittez ( q) lors de la première P2correspondance.

Cela échouera si un P2vient avant P1. Pour gérer ce cas, essayez:

sed -n '/P1/,/P2/{p; /P2/q}'
muru
la source
1
Je ne suis pas d'accord; La réponse de mikeserv n'est pas meilleure que la vôtre.
G-Man dit `` Réinstalle Monica '' le
@ g-man - pshaw. mais je pensais juste la même chose.
mikeserv
1
@gman - non. Maintenant je comprends. les mines bien mieux. pas de {stack}!
mikeserv
1

Si vous souhaitez ignorer les modèles eux-mêmes, voici la awkversion:

awk '/P2/ {exit} /P1/ {f=1; next} f' file
codeforester
la source
Travaille pour moi. Pourriez-vous ajouter plus d'informations sur le fonctionnement de la commande?
0xAffe
1

Une simple awksolution (tri de mi - chemin entre la réponse de Iruvar et  la réponse de Muru , mais pas en utilisant une variable):

awk '/P1/,/P2/ { print }  /P2/ { exit }'

et, comme l'a noté muru, si le premier P2 apparaît avant le premier P1, cela n'imprimera rien.

Bien sûr, si vous souhaitez imprimer toutes les plages P1-P2:

something P1 something
content1
content2
something P2 something
something P1 something
content3
content4
something P2 something

laissez de côté la exitpartie:

awk '/P1/,/P2/ { print }'
G-Man dit «Réintègre Monica»
la source
1
awk '/P1/,/P2/{print;f=1} f&&/P2/{exit}' data

Quittez immédiatement après l'impression, pas avant.

dedowsdi
la source
0

Pour ignorer les modèles eux-mêmes et n'afficher que le premier bloc correspondant dans un seul GNU sed:

sed -nre '/STARTPATTERN/ {:a;n;/ENDPATTERN/{b;};p;ba}' file
Santrix
la source