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.
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:
h
copie la première ligne dans l'espace hold.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.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.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.
@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:
-n
désactive la sortie sauf indication expliciteHost:
ligne dans le tampon d'attente (h)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é.
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.