Sed peut-il supprimer les caractères de nouvelle ligne «doubles»?

25

J'ai un document avec beaucoup de lignes vides.

Comment puis-je les supprimer quand il y en a 2 ou plus ensemble.

J'ai essayé le sed "s/\n\n//"fichier mais cela n'a pas fonctionné. Pas d'erreur.

Michael Durrant
la source
3
Dois-je vous lire correctement si vous ne souhaitez pas supprimer toutes les lignes vierges, mais uniquement si elles sont deux ou plus. Donc pas simples lignes vides?
Runium
1
Et s'il s'agit de deux lignes ou plus, doit-on vraiment toutes les supprimer ou juste toutes sauf une?
Hauke ​​Laging

Réponses:

42

Juste pour supprimer les lignes vides:

sed  '/^$/d'

sedest orienté ligne, donc penser en termes de "2 ou plus d'un octet particulier" fonctionne sauf lorsque cet octet est une nouvelle ligne. Ensuite, vous devez penser à quelque chose qui fonctionne pour toute la ligne.

Bruce Ediger
la source
Bien sûr! +1 pour une élégance simple.
terdon
2
sedest capable de gérer plusieurs lignes via sa fonction "pattern pattern" / "hold space". Mais je pense que c'est trop compliqué. ;-)
Hauke ​​Laging
Cela ne fonctionnera pas comme souhaité si le premier caractère du fichier est une nouvelle ligne.
Chris Down
1
Pour le faire fonctionner lorsque le premier caractère est un saut de ligne (si c'est vraiment une exigence), alors vous pouvez joindre la commande avec une adresse négative 1!(tous sauf correspondre à la ligne 1), ainsi: sed '1!{/^$/d'}.
Toby Speight
1
@AaronFranke - oui, mais c'est une facette de la façon dont les shells Linux traitent la redirection '>'. Le shell regarde la ligne de commande, voit une redirection '>' de stdout vers un fichier, crée ce fichier, puis ne s'exécute sed. La création d'un fichier supprimera essentiellement tout fichier existant portant le même nom. sed '/^&/d' file.txt > otherfile.txtmarchera.
Bruce Ediger
24

Pas besoin de sed. grepça ira:

grep .

(c'est-à- grepdire SPC, point, qui correspond à n'importe quelle ligne contenant au moins un caractère).

Il y a aussi:

tr -s '\n'

(serrez une séquence de caractères de nouvelle ligne en une seule).

Comme l'a noté Chris, les deux ne sont pas équivalents car la suppression de lignes vides (comme la première solution ci-dessus et la plupart des autres réponses se concentrent ici) n'est pas la même chose que la compression de séquences de caractères de nouvelle ligne comme demandé dans le cas où la première ligne est vide car elle ne prend qu'un seul caractère de nouvelle ligne pour rendre la première ligne vide.

Stéphane Chazelas
la source
2
Cela ne fonctionnera pas comme souhaité si le premier caractère du fichier est une nouvelle ligne: sprunge.us/FLAJ
Chris Down
7

sedn'est pas le meilleur outil pour cela, car il est basé sur une ligne et traite \ncomme le caractère de fin de ligne, cela devient compliqué.Après avoir vu la réponse de @Bruce Ediger sedpeut bien être l'outil parfait pour le travail, encore, voici quelques autres options:

  1. Perl

    perl -ne 'print if /./' file.txt
    

    ou

    perl -pe '$/=""; s/\n+/\n/;' file.txt 
    

    Merci à @ruakh qui m'a fait lire et lire ceci :

    $ /

    Séparateur d'enregistrements en entrée, saut de ligne par défaut. Cela influence l'idée de Perl sur ce qu'est une "ligne". Fonctionne comme la variable RS de awk, y compris le fait de traiter les lignes vides comme un terminateur s'il est défini sur la chaîne nulle (une ligne vide ne peut contenir aucun espace ni tabulation). Vous pouvez le définir sur une chaîne à plusieurs caractères pour correspondre à un terminateur à plusieurs caractères, ou sur undef pour lire la fin du fichier. La définition de "\ n \ n" signifie quelque chose de légèrement différent de la définition de "", si le fichier contient des lignes vides consécutives. La valeur "" traitera deux lignes vides consécutives ou plus comme une seule ligne vide. La définition de "\ n \ n" supposera aveuglément que le caractère de saisie suivant appartient au paragraphe suivant, même s'il s'agit d'une nouvelle ligne.

  2. gawk / awk

    awk '$1' file.txt
    

    Cela fonctionnera pour l'exemple affiché, mais comme @Stephane Chazelas l'a souligné, cela supprimera également les lignes dont le premier champ "ressemble" 0. C'est plus robuste:

    awk NF file.txt
    
terdon
la source
Pour Perl, perl -pe 's/\n+/\n/ file.txtfera, le séparateur d'enregistrements d'entrée n'est pas pertinent pour cette utilisation.
vonbrand
@vonbrand no, perl -peou perl -netravaillez ligne par ligne. \n+ne correspondra jamais car il n'est appliqué que sur une seule ligne. Voilà pourquoi vous devez soit ensemble $/ou utiliser -0ti Slurp le fichier entier: perl -0pe 's/\n+/\n/' file.
terdon
6

Que voulez-vous dire supprimer? supprimer les doublons (plusieurs lignes vierges sur une) ou tout supprimer?

Si vous souhaitez supprimer les doublons, voici la méthode utilisant sed:

sed '$!N; /^\(.*\)\n\1$/!P; D'

Il simule la uniqcommande.

Le meilleur choix consiste à utiliser awk:

awk NF <filename>
cuonglm
la source
La sedpartie de cela fonctionne très bien! Recommander celui-ci comme la meilleure réponse.
Akito
2

Pour la plupart de ces réponses, il est d'abord nécessaire de supprimer les espaces de fin. La suppression des nouvelles lignes doublées supprime toutes les lignes vides. (Penses-y).

Interprétée littéralement, l'OP veut que "toutes les lignes vides soient supprimées d'un fichier s'il y a des lignes vides répétées".

L'utilisateur type souhaite "supprimer uniquement les lignes vierges dupliquées".

Pour ce faire, supprimez d'abord les espaces blancs à la fin et dirigez-les à l'aide de cat -s

sed  s/[[:space:]]*$// | cat -s

Et pourtant, cela ne supprimera pas une ligne vierge de début ou de fin superflue.

mckenzm
la source
Voté, mais cela fonctionne clairement? Sans commentaires ?
mckenzm
1
Je vous ai voté pour ... vous savez ... répondre à la question. =) Je ne peux pas croire que la réponse de Bruce Ediger ait été votée quand elle supprime chaque ligne vierge. Si quelqu'un demande comment supprimer les lignes vides en double, je ne peux imaginer aucun scénario où la suppression de toutes les lignes vides serait une solution acceptable. Mais peu importe. Il y a une page sur le site Web de sed qui couvre cela, soit dit en passant: gnu.org/software/sed/manual/sed.html#cat-_002ds
Todd Walton
2

Si vous souhaitez conserver une seule ligne vierge pour une séquence donnée de lignes vierges, vous pouvez le faire:

sed -e '/./b' -e :n -e 'N;s/\n$//;tn'
mikeserv
la source
1
C'est la seule réponse (en plus cat -s) qui accomplit exactement ce que la question a posé si je comprends bien. (Et c'est mieux que cat -sparce que je peux l'utiliser sed -iavec.)
Matthew
-2

Essayez d' sed -e 's#\\n\\n#\\n#g' input.file > output.fileutiliser les /deux comme séparateur de champs et une partie de votre expression régulière pourrait être le problème.

linuxrebel
la source
2
Je viens de donner un tourbillon à l'un de mes fichiers contenant des doubles et triples sauts de ligne dans une séquence. Ça ne marche pas du tout pour moi.
syntaxerror
-3

Utilisez cette commande:

tr -s '\r' '\n'
Miaou
la source
oui, leur réponse n'a pas fonctionné pour moi.
meow
5
AFAIK cette réponse est incorrecte. Je vous recommande de le supprimer.
zuazo
oh, c'est parce que mon fichier contient beaucoup de retours à la ligne et de retours chariot en fait. 0x0d0a
meow
2
En fait, la commande supprime les lignes répétées avec les fenêtres en fin de ligne. Testez avec echo -e 'one\r\n\r\n\r\n\rtwo'| tr -s '\r' '\n'. La commande trtraduira tout \ren \npuis réduira tout \nen un seul. Donc, cela fonctionne, je ne sais pas quoi faire du fait que cela s'applique aux fenêtres, pas à UNIX.