Ma question est liée à la sed
solution spécifique donnée dans cette réponse pour cette question de grepping inverse . La sed
/ grep
solution 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.
sed
recette 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, voirtac
GNU coreutils.Réponses:
Cela inverse le fichier ligne par ligne.
Tout d'abord,
sed
a 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
sed
lecture 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
,h
et$!d
1!G
signifie que laG
commande est exécutée sur chaque ligne sauf la première (le!
nie le1
).G
signifie ajouter ce qui se trouve dans l'espace d'attente dans l'espace de motif.h
s'applique à chaque ligne. Il copie l'espace de motif dans l'espace d'attente (et l'écrase).$!d
s'applique à toutes les lignes sauf la dernière ($
représente la dernière ligne, la!
nie).d
est la commande pour supprimer la ligne (espace modèle).sed
exécute lah
commande. La première ligne est copiée dans l'espace d'attente. Il est ensuite supprimé, car il correspond à la$!
condition.sed
continue avec la deuxième ligne.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, lah
commande 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.$
), 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 .la source
h
commande copie l'espace de motif dans l'espace d'attente, qui persiste jusqu'à lased
fin. Après la fin du script, tout est effacé, car le binaire est sorti.sed
il n'y a qu'un seul espace d'attente. C'est comme une variable qui peut contenir quelque chose.-n
nous 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 lad
commande ne sera pas exécutée, la ligne est imprimée (cette ligne contient maintenant tout le fichier inversé).h
commande 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 dused
traitement de la dernière ligne d'entrée , leG
lit l'espace d'attente (afin de l'ajouter à l'espace modèle), puish
copie l'espace modèle dans l'espace d'attente, qui n'est plus jamais référencé . On pourrait tout aussi bien diresed 'G;$!h;$!d'
oused 'G;$!{h;d}'
. (2) Nous pourrions éviter d'utiliserd
en disantsed -n 'G;h;$p'
.