Comment supprimer des lignes vides à partir de la ligne 5

10

J'ai ceci:

sed -i '/^$/d' temp_spec.rb

qui supprime les lignes blanches et fonctionne bien. Comment puis-je le faire uniquement pour les lignes 5-999 (ou idéalement 5 à la fin du fichier).

J'ai essayé:

sed -n5,999 -i '/^$/d' temp_spec.rb
sed '5,999!d/^$/d' temp_spec.rb

mais aucun n'a fonctionné (pas d'erreurs).

Michael Durrant
la source
Juste pour être sûr: voulez-vous conserver les lignes 1 à 4, qu'elles soient vides ou non, ou voulez-vous supprimer les lignes 1 à 4, qu'elles soient vides ou non? (Jusqu'à présent, j'ai supposé le premier, mais le deuxième commandement que vous avez essayé me fait me demander.)
Uwe

Réponses:

12

Si vous souhaitez supprimer toutes les lignes vides commençant par la ligne 5 et conserver les lignes 1 à 4, vous pouvez utiliser

sed -i '5,${;/^$/d;}' temp_spec.rb

L' {opérateur de regroupement est donc la première commande 5,${signifie "de la ligne 5 jusqu'à la fin de input ( $) exécuter les commandes suivantes jusqu'à la correspondance }". Les commandes entre {et }peuvent à nouveau être préfixées par des adresses, donc la commande interne /^$/dsignifie "s'il n'y a rien entre le début ( ^) et la fin ( $) de la ligne, supprimez-la". Les commandes sed peuvent être séparées par ;. (Il s'agit d'une fonctionnalité mal documentée de sed. Elle est prise en charge par la plupart des implémentations sed, mais elle n'est pas entièrement portable .) Comme indiqué par Hauke, l' ;after {est facultatif; la précédente }est cependant requise.

Si vous souhaitez supprimer toutes les lignes vides commençant par la ligne 5 et également supprimer les lignes 1 à 4, c'est plus simple:

sed -i '1,4d;/^$/d' temp_spec.rb
Uwe
la source
Agréable. Je ne savais pas que les adresses pouvaient être imbriquées de cette façon. Pour moi, cela fonctionne aussi sans leader ;.
Hauke ​​Laging
Oui, vous avez raison sur le premier ;.
Uwe
@Hauke ​​Laging Vous pouvez séparer les commandes d'un script sed par ';' au lieu de les mettre sur des lignes séparées. Il s'agit d'une fonctionnalité "non documentée".
Predrag Punosevac
4

Une autre option en utilisant awk:

awk 'NR<5||/./'
Lri
la source
2
sed '5,${s/^$//; t delete; b end; : delete; d; : end;}' temp_spec.rb

Modifier 1:

Je suis censé expliquer cela, donc ...

C'est inutilement compliqué. Je ne savais pas que les plages d'adresses sont autorisées à l'intérieur {}. J'ai donc dû exprimer «supprimer les lignes vides» différemment. La commande principale est tcelle de sed if ... then. Taurait été plus facile mais n'est disponible que pour GNU sed. Je cite la page de manuel:

étiquette t: si as /// a effectué une substitution réussie depuis la lecture de 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.

J'abuse de la fameuse scommande. Il ne remplacera rien mais testera seulement si la ligne est vide. Donc, il remplace une ligne vide par une ligne vide (pourrait utiliser n'importe quoi comme remplacement car la ligne est supprimée de toute façon).

Si sa fait un "remplacement" alors la ligne est vide. Dans ce cas, la commande ddoit être exécutée. Sinon, rien ne doit être fait. Comme tne saute pas en cas d' saction j'ai besoin de la commande branch bpour sauter à la fin du script. : labelsont des cibles de branche. Comme gotoà l'époque dans les âges sombres (quand sed a été inventé ... te-hee).

Une autre option serait de s"remplacer" toutes les lignes non vides, ce qui rend la commande splus compliquée mais plus simple:

sed '5,${s/^\(..*\)$/\1/; t end; d; : end;}' input

^..*$signifie "ligne non vide" et \1signifie "le contenu des premières parenthèses".

Hauke ​​Laging
la source
Un peu d'explication pour OP (je peux sentir leur cerveau essayer de ramper à travers les oreilles en lisant ceci ...)
vonbrand