Comment la commande sed '1! G; h; $! D' inverse-t-elle le contenu d'un fichier?


20

Ma question est liée à la sedsolution spécifique donnée dans cette réponse pour cette question de grepping inverse . La sed/ grepsolution que je n'arrive pas à déchiffrer est la suivante:

sed '1!G;h;$!d' file

Quelqu'un peut-il déchiffrer cette commande?

Je sais par VI (M) que G désigne la dernière ligne du fichier et qu'en sed un bang (!) Suivi d'une adresse fonctionne un peu comme grep -vça c'est-à-dire qu'il ne correspondra pas à cette ligne. Mais dans l'ensemble, le script sed en ligne ci-dessus me dépasse.


3
... très lentement ...
mikeserv

1
Comme l'indique mikeserv. Il convient de noter que cette sedrecette délicate est un moyen extrêmement inefficace (complexité O (n ^ 2/2)) d'inverser les lignes d'un fichier. Ce serait trop lent pour les fichiers avec un grand nombre de lignes. Pour une alternative d'inversion d'ordre de ligne beaucoup plus efficace, voir tacGNU coreutils.
arielf

Réponses:


35

Cela inverse le fichier ligne par ligne.

fichier sed '1! G; h; $! d'

Tout d'abord, seda un espace d'attente et un espace de motif . Nous devons les distinguer avant de nous concentrer sur cette commande spécifique.

Lors de la sedlecture d'une nouvelle ligne, elle est chargée dans l'espace de motif. Par conséquent, cet espace est écrasé chaque fois qu'une nouvelle ligne est traitée. D'un autre côté, l'espace de maintien est cohérent sur l'ensemble du traitement et les valeurs peuvent y être stockées pour une utilisation ultérieure.


À la commande:

Il y a 3 commandes dans cette déclaration: 1!G, het$!d

  • 1!Gsignifie que la Gcommande est exécutée sur chaque ligne sauf la première (le !nie le 1). Gsignifie ajouter ce qui se trouve dans l'espace d'attente dans l'espace de motif.

  • hs'applique à chaque ligne. Il copie l'espace de motif dans l'espace d'attente (et l'écrase).

  • $!ds'applique à toutes les lignes sauf la dernière ( $représente la dernière ligne, la !nie). dest la commande pour supprimer la ligne (espace modèle).


  1. Maintenant, lorsque la première ligne est lue, sedexécute la hcommande. La première ligne est copiée dans l'espace d'attente. Il est ensuite supprimé, car il correspond à la $!condition. sedcontinue avec la deuxième ligne.
  2. La deuxième ligne correspond à la condition 1!(ce n'est pas la première ligne), et donc l'espace d'attente (qui a la première ligne) est ajouté à l'espace de motif (qui a la deuxième ligne). Après cela, dans l'espace de motif, il y a maintenant la deuxième ligne suivie de la première ligne, délimitée par une nouvelle ligne. Maintenant, la hcommande s'applique (comme dans chaque ligne); tout ce qui se trouve dans l'espace de motif est copié dans l'espace d'attente. La troisième instruction ( $!d) s'applique: la ligne est supprimée de l'espace de motif.
  3. L'étape 2 est maintenant effectuée avec toutes les lignes. Nous sautons à la dernière ligne.
  4. Dans la dernière ligne ( $), presque toute l'étape 2 est terminée, mais pas la partie de suppression ( d). sed, lorsqu'il est appelé sans -n, imprime automatiquement l'espace de motif à la fin du traitement pour chaque ligne d'entrée. Ainsi, lorsqu'il n'est pas supprimé, l'espace de motif est imprimé. Il contient désormais toutes les lignes dans l' ordre inverse .

1
@Geek Non, la hcommande copie l'espace de motif dans l'espace d'attente, qui persiste jusqu'à la sedfin. Après la fin du script, tout est effacé, car le binaire est sorti.
chaos

2
Pouvons-nous penser à l'espace d'attente comme des registres pour vim? Sont-ils également numérotés? Ou il n'y en a qu'un seul?
Geek

2
@Geek In, sedil n'y a qu'un seul espace d'attente. C'est comme une variable qui peut contenir quelque chose.
chaos

1
@ user1717828 Si nous ne le faisions pas, la première ligne serait imprimée lors du traitement. Puisque sed n'est pas invoqué avec, -nnous devons supprimer toutes les lignes sauf la dernière. À la dernière ligne, sed ajoute tout, de l'espace de maintien à l'espace de motif. Et parce que la dcommande ne sera pas exécutée, la ligne est imprimée (cette ligne contient maintenant tout le fichier inversé).
chaos

1
(1) La sous-question / observation du PO (dans le commentaire) est, "donc la hcommande sur la dernière ligne est en quelque sorte un non-op." (Avec un accent supplémentaire et légèrement paraphrasé). Il a raison; lors du sedtraitement de la dernière ligne d'entrée , le Glit l'espace d'attente (afin de l'ajouter à l'espace modèle), puis hcopie l'espace modèle dans l'espace d'attente, qui n'est plus jamais référencé . On pourrait tout aussi bien dire sed 'G;$!h;$!d'ou sed 'G;$!{h;d}'. (2) Nous pourrions éviter d'utiliser den disant sed -n 'G;h;$p'.
Scott
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.