Quelle est la signification de: a; $! N; dans une commande sed?

11
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

La sedcommande ci- dessus remplace le nouveau caractère de ligne par la chaîne "chaîne". Mais je ne connais pas le sens des :a;$!N;s/\n/string/;taguillemets simples. Je connais la partie médiane s/\n/string/. Mais je ne connais pas la fonction de la première ( :a;$!N;) et de la dernière ( ta) partie.

Avinash Raj
la source
2
veuillez consulter stackoverflow.com/questions/1251999/… .
xiaodongjie
Et la dernière partie?
Avinash Raj
La commande "t" se branche sur une étiquette nommée si la dernière commande de substitution a modifié l'espace de motif.
xiaodongjie

Réponses:

17

Ce sont les commandes, certes énigmatiques sed. Plus précisément (de man sed):

: label
         Libellé pour les commandes b et t.

étiquette t
         Si as /// a effectué une substitution réussie depuis la dernière ligne d'entrée et depuis la dernière commande t ou T, branchez-vous sur étiquette; si l'étiquette est omise, branchez-vous à la fin du script.

n N Lire / ajouter la ligne d'entrée suivante dans l'espace de motif.

Ainsi, le script que vous avez publié peut être décomposé en (espaces ajoutés pour plus de lisibilité):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

Fondamentalement, ce que cela fait pourrait être écrit en pseudocode comme

while (not end of line){
    append current line to this one and replace \n with 'string'
}

Vous pouvez mieux comprendre cela avec un exemple d'entrée plus complexe:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

Je ne sais pas vraiment pourquoi cela !$est nécessaire. Autant que je sache, vous pouvez obtenir la même sortie avec

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'
terdon
la source
1
Le! $ Ne doit pas correspondre à la dernière nouvelle ligne, IMO.
Braiam
@Braiam n'en est pas trop sûr, ce n'est $!pas le cas !$. Cependant, cela pourrait aussi être le cas !Net non $!.
terdon
J'ai essayé d'analyser la page texinfo , mais n'a pas trouvé de références ni à !Nou $!. Donc, je continue de penser que la dernière ligne est la nouvelle ligne ou l'EOF.
Braiam
4
J'essaie de penser $!à une «plage» d'adresses avec un opérateur de complément postfix - donc $!N(faire Npartout sauf pour l'adresse $) est vraiment la même syntaxe que quelque chose comme m,n!d(supprimer tout sauf les lignes mvers n).
steeldriver
:est analogue au gotolabel, et en fait :était un label goto dans le shell Thompson, donc il serait familier aux gens à l'époque utilisant sed et le shell Thompson
Sergiy Kolodyazhnyy
0

Je poste cette réponse car je vois beaucoup de confusion sur la raison pour laquelle la dernière ligne est exclue lors de l'exécution N(via la chaîne d'adressage de ligne $!) et parce que l'OP était confus quant à la signification de :a;$!N; dans une commande sed , pas seulement dans celle spécifique qu'il a postée .

Eh bien, l'avantage d'utiliser $!Nau lieu de Nn'est pas évident dans les exemples proposés (par l'OP et par @terdon), car aucune commande "importante" (continuer à lire) n'est exécutée sur la dernière ligne après la Ncommande. (En effet, le résultat est le même si l'on supprime cette adresse de ligne.)

Dans un exemple plus complexe (par exemple, remplacer this sentencedans un fichier, les deux mots apparaissant parfois sur une ligne et d'autres fois sur deux lignes), l'exclusion de la dernière ligne de la Ncommande pourrait être cruciale! Si la dernière ligne n'est pas exclue, lors de l'exécution Nsur elle, sedfrappe EOFet quitte immédiatement, empêchant toutes les commandes suivantes (commandes de branchement également, à savoir tet b) d'être exécutées.

Dans les exemples trop simplistes illustrés, nous pouvons supprimer $!et laisser sedéchouer l'exécution Net le retour en toute sécurité car la scommande abandonnée ne ferait rien si elle était exécutée, car il n'y a pas \nde correspondance.

Enrico Maria De Angelis
la source