web-dev-qa-db-fra.com

Imprimer avec sed ou awk une ligne suivant un motif correspondant

J'aimerais imprimer une seule ligne directement après une ligne contenant un motif correspondant. Ma version de sed ne prendra pas la syntaxe suivante (elle explose sur +1p.), Ce qui semble être une solution simple:

sed -n '/ABC/,+1p' infile

Je suppose que awk serait préférable pour le traitement multiligne, mais je ne sais pas comment le faire.

47
user1537723

Ne jamais utiliser le mot "modèle" car il est très ambigu. Utilisez toujours "string" ou "regexp" (ou dans le "motif globbing" de Shell), quel que soit le mot que vous entendez vraiment.

La réponse spécifique que vous voulez est:

awk 'f{print;f=0} /regexp/{f=1}' file

ou en spécialisant la solution plus générale du nième enregistrement après une expression rationnelle (idiome "c" ci-dessous):

awk 'c&&!--c; /regexp/{c=1}' file

Les expressions suivantes décrivent comment sélectionner une plage d'enregistrements en fonction d'une expression rationnelle spécifique:

a) Imprimez tous les enregistrements de certaines expressions rationnelles:

awk '/regexp/{f=1}f' file

b) Imprimez tous les enregistrements après une expression rationnelle:

awk 'f;/regexp/{f=1}' file

c) Imprimez le Nième enregistrement après une expression rationnelle:

awk 'c&&!--c;/regexp/{c=N}' file

d) Imprimer tous les enregistrements sauf le Nième après une expression rationnelle:

awk 'c&&!--c{next}/regexp/{c=N}1' file

e) Imprimez les N enregistrements après une expression rationnelle:

awk 'c&&c--;/regexp/{c=N}' file

f) Imprimez tous les enregistrements sauf les N après une expression rationnelle:

awk 'c&&c--{next}/regexp/{c=N}1' file

g) Imprimez les N enregistrements de certaines expressions rationnelles:

awk '/regexp/{c=N}c&&c--' file

J'ai changé le nom de la variable de "f" pour "trouvé" en "c" pour "compte", où Est approprié car c'est plus représentatif de ce que la variable est réellement.

112
Ed Morton

C'est la ligne après qui correspond dans laquelle vous êtes intéressant, non? Dans sed, cela pourrait être accompli comme suit:

sed -n '/ABC/{n;p}' infile

Vous pouvez également choisir l’optionAde grep.

-A NUM, Print NUM lines of trailing context after matching lines.

Par exemple, étant donné le fichier d'entrée suivant:

foo
bar
baz
bash
bongo

Vous pouvez utiliser les éléments suivants:

$ grep -A 1 "bar" file
bar
baz
$ sed -n '/bar/{n;p}' file
baz

J'espère que cela pourra aider.

32
chooban

J'avais besoin d'imprimer TOUTES les lignes après le motif (ok Ed, REGEX), alors j'ai choisi celui-ci:

sed -n '/pattern/,$p' # prints all lines after ( and including ) the pattern

Mais puisque je voulais imprimer toutes les lignes APRES (et exclure le motif) 

sed -n '/pattern/,$p' | tail -n+2  # all lines after first occurrence of pattern

Je suppose que dans votre cas, vous pouvez ajouter un head -1 à la fin

sed -n '/pattern/,$p' | tail -n+2 | head -1 # prints line after pattern
3
Mark

version awk:

awk '/regexp/ { getline; print $0; }' filetosearch
2
tue

Si le motif correspond, copiez la ligne suivante dans le tampon de motifs, supprimez un retour, puis quittez - l’effet secondaire consiste à imprimer.

sed '/pattern/ { N; s/.*\n//; q }; d'
1
Michael Back

En fait, sed -n '/pattern/{n;p}' filename échouera si les pattern correspondent aux lignes continuous:

$ seq 15 |sed -n '/1/{n;p}'
2
11
13
15

Les réponses attendues devraient être:

2
11
12
13
14
15

Ma solution est:

$ sed -n -r 'x;/_/{x;p;x};x;/pattern/!s/.*//;/pattern/s/.*/_/;h' filename

Par exemple:

$ seq 15 |sed -n -r 'x;/_/{x;p;x};x;/1/!s/.*//;/1/s/.*/_/;h'
2
11
12
13
14
15

Explique:

  1. x;: au début de chaque ligne de l'entrée, utilisez la commande x pour échanger le contenu dans pattern space & hold space.
  2. /_/{x;p;x};: si pattern space, qui est en réalité le hold space, contient _ (il s’agit simplement d’un indicator indiquant si la dernière ligne correspondait à pattern ou non), utilisez x pour échanger le contenu réel de current line en pattern space, utilisez p pour imprimer current line, x pour récupérer cette opération. 
  3. x: récupérer le contenu dans pattern space et hold space.
  4. /pattern/!s/.*//: si current line ne correspond PAS à pattern, ce qui signifie que nous ne devrions PAS imprimer la ligne suivante, utilisez ensuite la commande s/.*// pour supprimer tout le contenu de pattern space.
  5. /pattern/s/.*/_/: si current line correspond à pattern, ce qui signifie que nous devrions imprimer la ligne suivante, alors nous devons définir un indicator pour indiquer à sed d'imprimer la ligne NEXT, utilisez donc s/.*/_/ pour remplacer tout le contenu de pattern space par un _ (la deuxième commande sera utilisée). de juger si la dernière ligne correspond à la variable pattern ou non).
  6. h: écrase le hold space avec le contenu dans pattern space; alors, le contenu dans hold space est ^_$, ce qui signifie que current line correspond à la pattern ou ^$, ce qui signifie que current line ne correspond PAS à la pattern.
  7. les cinquième et sixième étapes ne peuvent PAS être échangées, car après s/.*/_/, le pattern space ne peut PAS correspondre à /pattern/; le s/.*// DOIT donc être exécuté!
1
Weike

Cela pourrait fonctionner pour vous (GNU sed):

sed -n ':a;/regexp/{n;h;p;x;ba}' file

Utilisez l'option -n de type seds grep et si la ligne actuelle contient l'expression rationnelle requise, remplacez la ligne actuelle par la suivante, copiez cette ligne dans l'espace de conservation (HS), imprimez la ligne, échangez l'espace de modèle (PS) pour le HS et répéter.

0
potong