web-dev-qa-db-fra.com

Le concept de `` Hold Space '' et de `` Pattern Space '' dans Sed

Je suis confus par les deux concepts de sed: espace de maintien et espace de motif. Quelqu'un peut-il aider à les expliquer?

Voici un extrait du manuel:

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

Ces six commandes me confondent vraiment.

66
ChenQi

Lorsque sed lit un fichier ligne par ligne, la ligne qui est actuellement lue est insérée dans le ( motif tampon (espace modèle). Le tampon de modèle est comme le tampon temporaire, le bloc-notes où sont stockées les informations actuelles. Lorsque vous dites à sed d'imprimer, il imprime le tampon de motif.

Hold buffer/hold space est comme un stockage à long terme, de sorte que vous pouvez attraper quelque chose, le stocker et le réutiliser plus tard lorsque sed traite une autre ligne. Vous ne traitez pas directement l'espace d'attente, mais vous devez le copier ou l'ajouter à l'espace de motif si vous voulez en faire quelque chose. Par exemple, la commande d'impression p imprime uniquement l'espace de motif. De même, s opère sur l'espace modèle.

Voici un exemple:

sed -n '1!G;h;$p'

(l'option -n supprime l'impression automatique des lignes)

Il y a trois commandes ici: 1!G, h et $p. 1!G a une adresse, 1 (première ligne), mais le ! signifie que la commande sera exécutée partout mais sur la première ligne. $p par contre ne sera exécuté que sur la dernière ligne. Donc, ce qui se passe est le suivant:

  1. la première ligne est lue et insérée automatiquement dans l'espace de motif
  2. sur la première ligne, la première commande n'est pas exécutée; h copie la première ligne dans l'espace hold.
  3. maintenant la deuxième ligne remplace tout ce qui était dans l'espace de motif
  4. sur la deuxième ligne, nous exécutons d'abord G, en ajoutant le contenu du tampon de maintien au tampon de modèle, en le séparant par une nouvelle ligne. L'espace de motif contient maintenant la deuxième ligne, une nouvelle ligne et la première ligne.
  5. Ensuite, la commande h insère le contenu concaténé du tampon de modèle dans l'espace d'attente, qui contient désormais les lignes inversées deux et un.
  6. Nous passons à la ligne numéro trois - allez au point (3) ci-dessus.

Enfin, une fois que la dernière ligne a été lue et que l'espace d'attente (contenant toutes les lignes précédentes dans un ordre inverse) a été ajouté à l'espace de motif, l'espace de motif est imprimé avec p. Comme vous l'avez deviné, ce qui précède fait exactement ce que fait la commande tac - imprime le fichier à l'envers.

92
January

@Ed Morton: Je suis en désaccord avec vous ici. J'ai trouvé sed très utile et simple (une fois que vous maîtrisez le concept du motif et maintenez les tampons) pour trouver une manière élégante de faire un grepping multiligne.

Par exemple, prenons un fichier texte qui contient des noms d'hôtes et quelques informations sur chaque hôte, avec beaucoup de déchets entre eux dont je ne me soucie pas.

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

Pour moi, un script awk pour obtenir simplement les lignes avec le nom d'hôte et la ligne info correspondante prendrait un peu plus que ce que je peux faire avec sed:

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

la sortie ressemble à:

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

(Notez que Host: foo1 apparaît deux fois dans la sortie.)

Explication:

  1. -n désactive la sortie sauf indication explicite
  2. premier match, trouve et met le Host: ligne dans le tampon d'attente (h)
  3. deuxième correspondance, trouve la ligne Info: suivante, mais échange d'abord (x) la ligne actuelle dans le tampon de modèle avec le tampon de maintien et affiche (p) le Host: ligne, puis rééchange (x) et imprime (p) la ligne Info :.

Oui, c'est un exemple simpliste, mais je soupçonne que c'est un problème courant qui a été rapidement traité par un simple paquebot sed. Pour des tâches beaucoup plus complexes, telles que celles dans lesquelles vous ne pouvez pas compter sur une séquence prévisible donnée, awk peut être mieux adapté.

13
Jens Jensen

Bien que la réponse de @ January et l'exemple soient Nice, l'explication ne m'a pas suffi. J'ai dû chercher et apprendre beaucoup jusqu'à ce que je réussisse à comprendre exactement sed -n '1!G;h;$p' travaux. Je voudrais donc développer la commande pour quelqu'un comme moi.

Voyons d'abord ce que fait la commande.

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

Il inverse l'entrée comme le fait la commande tac.

sed lit ligne par ligne, voyons donc ce qui se passe sur l'espace de patten et le tenir un espace à chaque ligne. Comme la commande h copie le contenu de l'espace de motif dans l'espace d'attente, les deux espaces ont le même texte.

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

À la dernière ligne, $p imprime d\nc\nb\na$ qui est formaté en

d
c
b
a

Si vous voulez voir l'espace modèle pour chaque ligne, vous pouvez ajouter une commande l.

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

J'ai trouvé très utile de regarder ce tutoriel vidéo Comprendre comment fonctionne sed , car le gars montre comment chaque espace sera utilisé étape par étape. La prise espacée est référencée dans le 4ème tutoriel, mais je recommande de regarder toutes les vidéos si vous n'êtes pas familier avec sed.

Aussi document GNU sed et Bruce Barnett Sed tutorial sont de très bonnes références.

9
Sanghyun Lee