1551 votes

Comment remplacer un saut de ligne ( \n ) en utilisant sed ?

Comment remplacer un saut de ligne (" \n ") avec un espace (" ") en utilisant le sed commande ?

J'ai essayé sans succès :

sed 's#\n# #g' file
sed 's#^$# #g' file

Comment puis-je le réparer ?

38 votes

tr n'est le bon outil pour le travail que si l'on remplace un caractère unique par un caractère unique, alors que l'exemple ci-dessus montre remplacer newline par un espace . Donc, dans l'exemple ci-dessus, tr pourrait fonctionner Mais serait limitatif par la suite.

0 votes

@Mayhem, sed 's/$/ NewDelim/' | tr '\n' ' ' . Utilisez sed pour ajouter le nouveau délimiteur à la fin de chaque ligne, puis supprimer les retours à la ligne avec la commande tr . Moins énigmatique que le sed la seule façon, IMO.

13 votes

tr dans le bon outil pour le travail parce que le questionneur voulait remplacer chaque nouvelle ligne par un espace, comme indiqué dans son exemple. Le remplacement des retours à la ligne n'est qu'une bizarrerie pour sed mais facilement réalisable par tr . Il s'agit d'une question courante. L'exécution de remplacements d'expressions rationnelles n'est pas effectuée par tr mais par sed qui serait le bon outil... pour une autre question.

1858voto

dmckee Points 50318

sed est destiné à être utilisé sur une entrée de type ligne. Bien qu'il puisse faire ce dont vous avez besoin.


Une meilleure option ici est d'utiliser l'option tr comme suit :

tr '\n' ' ' < input_filename

ou supprimer entièrement les caractères de nouvelle ligne :

tr -d '\n' < input.txt > output.txt

ou si vous avez la version GNU (avec ses longues options)

tr --delete '\n' < input.txt > output.txt

0 votes

Je ne comprends pas pourquoi sed ne peut pas le faire. S'il vous plaît, clarifiez pour utiliser un autre outil.

98 votes

Sed est basé sur les lignes, il est donc difficile pour lui de saisir les nouvelles lignes.

1 votes

Alexander : Est-ce que "stream editor" signifie "basé sur la ligne" ? Peut-être que le nom prête à confusion.

1662voto

Zsolt Botykai Points 20615

Utilisez cette solution avec GNU sed :

sed ':a;N;$!ba;s/\n/ /g' file

Cette méthode lit le fichier entier en boucle, puis remplace les nouvelles lignes par des espaces.

Explication :

  1. Créer une étiquette via :a .
  2. Ajouter la ligne actuelle et la ligne suivante à l'espace du motif via N .
  3. Si nous sommes avant la dernière ligne, passer à l'étiquette créée $!ba ( $! signifie qu'il ne faut pas le faire sur la dernière ligne car il doit y avoir un dernier saut de ligne).
  4. Enfin, la substitution remplace chaque nouvelle ligne par un espace sur l'espace du motif (qui est le fichier entier).

Voici une syntaxe compatible avec les plateformes, qui fonctionne avec BSD et OS X. sed (selon Commentaire de @Benjie ) :

sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g' file

Comme vous pouvez le constater, l'utilisation de sed pour ce problème autrement simple est problématique. Pour une solution plus simple et adéquate, voir cette réponse .

120 votes

Vous pouvez l'exécuter sur plusieurs plates-formes (c'est-à-dire sur Mac OS X) en exécutant séparément les commandes plutôt que de les séparer par des points-virgules : sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'

3 votes

Il semble ne pas supprimer le dernier \n ?

0 votes

Voir le numéro 3 ci-dessus. Il semble que $ ! signifie qu'il ne faut pas le faire sur la dernière ligne car il devrait y avoir un dernier saut de ligne.

565voto

hdorio Points 3332

Réponse rapide

sed ':a;N;$!ba;s/\n/ /g' file
  1. :a créez une étiquette "a
  2. N ajoute la ligne suivante à l'espace du motif
  3. $ ! si ce n'est pas la dernière ligne , ba branche (aller à) étiquette "a
  4. s substitut , / \n / regex pour une nouvelle ligne , / / par un espace , /g match global (autant de fois qu'il le peut)

sed passera en boucle les étapes 1 à 3 jusqu'à ce qu'il atteigne la dernière ligne, en obtenant que toutes les lignes s'insèrent dans l'espace du motif où sed substituera toutes les lignes \n caractères


Alternatives

Toutes les alternatives, contrairement sed n'auront pas besoin d'atteindre la dernière ligne pour commencer le processus

con bash , lent

while read line; do printf "%s" "$line "; done < file

con perl , sed -une vitesse similaire

perl -p -e 's/\n/ /' file

con tr plus rapide que sed peut être remplacé par un seul caractère

tr '\n' ' ' < file

con pâte , tr -comme la vitesse, peut être remplacé par un seul personnage

paste -s -d ' ' file

con awk , tr -une vitesse similaire

awk 1 ORS=' ' file

D'autres alternatives comme "echo $(<fichier)" est lent, ne fonctionne que sur les petits fichiers et doit traiter le fichier entier pour commencer le processus.


Longue réponse du sed FAQ 5.10

5.10. Pourquoi ne puis-je pas faire correspondre ou supprimer une nouvelle ligne en utilisant la fonction \n s'échapper
séquence ? Pourquoi je ne peux pas faire correspondre 2 lignes ou plus en utilisant \n ?

El \n ne correspondra jamais au saut de ligne en fin de ligne, car la fonction
la nouvelle ligne est toujours supprimée avant que la ligne ne soit placée dans le dossier de l'utilisateur.
espace pour les motifs. Pour placer 2 lignes ou plus dans l'espace du motif, utilisez
la commande 'N' ou quelque chose de similaire (comme 'H ;...;g;').

Sed fonctionne de la manière suivante : sed lit une ligne à la fois, coupe le
le saut de ligne de fin, met ce qui reste dans l'espace du motif où
le sed script peut l'aborder ou le modifier, et lorsque l'espace de motif
est imprimée, ajoute un saut de ligne à stdout (ou à un fichier). Si le
l'espace du motif est entièrement ou partiellement supprimé avec "d" ou "D", l'élément
la nouvelle ligne est no ajoutés dans de tels cas. Ainsi, des scripts comme

  sed 's/\n//' file       # to delete newlines from each line             
  sed 's/\n/foo\n/' file  # to add a word to the end of each line         

ne fonctionnera JAMAIS, car la nouvelle ligne de fin est supprimée. antes de
la ligne est placée dans l'espace des motifs. Pour effectuer les tâches ci-dessus,
utilisez l'un de ces scripts à la place :

  tr -d '\n' < file              # use tr to delete newlines              
  sed ':a;N;$!ba;s/\n//g' file   # GNU sed to delete newlines             
  sed 's/$/ foo/' file           # add "foo" to end of each line          

Étant donné que les versions de sed autres que GNU sed ont des limites à la taille des fichiers
le tampon de motifs, l'utilitaire Unix 'tr' est à préférer ici.
Si la dernière ligne du fichier contient un saut de ligne, GNU sed ajoutera
cette nouvelle ligne à la sortie mais supprime toutes les autres, alors que tr va
supprimer tous les retours à la ligne.

Pour faire correspondre un bloc de deux lignes ou plus, il existe trois choix de base :
(1) utilisez la commande 'N' pour ajouter la ligne suivante à l'espace du motif ;
(2) utilisez la commande 'H' au moins deux fois pour ajouter la ligne en cours.
à l'espace Hold, puis récupérer les lignes de l'espace Hold
avec x, g, ou G ; ou (3) utiliser des plages d'adresses (voir section 3.3, ci-dessus)
pour faire correspondre les lignes entre deux adresses spécifiées.

Les choix (1) et (2) mettront une \n dans l'espace du modèle, où il
peuvent être adressés comme on le souhaite ('s/ABC \nXYZ /alphabet/g'). Un exemple
l'utilisation de 'N' pour supprimer un bloc de lignes apparaît dans la section 4.13.
("Comment supprimer un bloc de spécifique lignes consécutives ?"). Ce site
L'exemple peut être modifié en remplaçant la commande de suppression par quelque chose comme
autre, comme 'p' (imprimer), 'i' (insérer), 'c' (changer), 'a' (ajouter),
ou "s" (substitut).

Le choix (3) ne mettra pas un \n dans l'espace du modèle, mais il hace
correspondre à un bloc de lignes consécutives, il se peut donc que vous ne
même besoin de la \n pour trouver ce que vous cherchez. Depuis que GNU sed
La version 3.02.80 prend désormais en charge cette syntaxe :

  sed '/start/,+4d'  # to delete "start" plus the next 4 lines,           

en plus de la gamme traditionnelle "/d'ici/,/de là/{...}".
il peut être possible d'éviter l'utilisation de \n entièrement.

0 votes

Merci pour la commande coller. Je ne la connaissais pas. J'ai un fichier contenant des URL et je voulais les ouvrir toutes en même temps dans le navigateur Chrome. C'est ce que j'ai fait (sur Mac OS X) : paste -s -d ' ' url.txt | xargs open Il fonctionne très bien.

0 votes

@xl-t vous devriez utiliser xargs -a url.txt open au lieu de

0 votes

Bonne réponse. Il y a un léger problème dans l'alternative bash. Elle échoue sur les lignes qui sont interprétées comme des interrupteurs pour echo. C'est pourquoi je n'utilise jamais echo pour imprimer des données variables. Utilisez printf '%s' "$line " à la place.

238voto

Thor Points 13562

Une alternative awk plus courte :

awk 1 ORS=' '

Explication

Un programme awk est construit à partir de règles qui consistent en des blocs de code conditionnels, c'est-à-dire.. :

condition { code-block }

Si le bloc de code est omis, la valeur par défaut est utilisée : { print $0 } . Ainsi, le 1 est interprété comme une condition vraie et print $0 est exécuté pour chaque ligne.

Lorsque awk lit l'entrée, il la divise en enregistrements basés sur la valeur de RS (séparateur d'enregistrement), qui est par défaut une nouvelle ligne, donc awk analysera par défaut l'entrée par ligne. Le découpage implique également de supprimer RS de l'enregistrement d'entrée.

Maintenant, lors de l'impression d'un enregistrement, ORS (Output Record Separator) lui est ajouté, par défaut c'est encore une nouvelle ligne. Ainsi, en modifiant ORS en espace, tous les retours à la ligne sont transformés en espaces.

5 votes

J'aime beaucoup cette solution simple, qui est beaucoup plus lisible que les autres.

9 votes

Si cela a plus de sens, cela pourrait effectivement être écrit comme suit : awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt (en ajoutant un saut de ligne final juste pour illustrer le début/la fin) ; le "1" est évalué à true (traiter la ligne) et print (imprimer la ligne). On peut également ajouter une condition à cette expression, par exemple, ne travailler que sur les lignes correspondant à un motif : awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '

2 votes

Vous pouvez le faire plus simplement : code awk 'ORS=" "' fichier.txt code

92voto

ire_and_curses Points 32802

El Perl fonctionne comme vous l'aviez prévu.

perl -i -p -e 's/\n//' file

Comme indiqué dans les commentaires, il convient de noter que cette modification est en place. -i.bak vous donnera une sauvegarde du fichier original avant le remplacement au cas où votre expression régulière n'est pas aussi intelligent que tu le pensais.

27 votes

Veuillez au moins mentionner que -i sans suffixe fait aucune sauvegarde . -i.bak vous protège d'une erreur facile et laide (par exemple, oublier de taper -p et la mise à zéro du fichier).

6 votes

@Telemachus : C'est un point juste, mais on peut l'argumenter dans les deux sens. La principale raison pour laquelle je ne l'ai pas mentionné est que l'exemple sed dans la question de l'OP ne fait pas de sauvegardes, donc cela semble superflu ici. L'autre raison est que je n'ai jamais vraiment utilisé la fonctionnalité de sauvegarde (je trouve les sauvegardes automatiques ennuyeuses, en fait), donc j'oublie toujours qu'elle est là. La troisième raison est que cela rallonge ma ligne de commande de quatre caractères. Pour le meilleur ou pour le pire (probablement pour le pire), je suis un minimaliste compulsif ; je préfère simplement la brièveté. Je sais que vous n'êtes pas d'accord. Je ferai de mon mieux pour ne pas oublier d'avertir des sauvegardes à l'avenir.

6 votes

@Ire_and_curses : En fait, tu viens de donner un très bon argument pour m'ignorer. C'est-à-dire que vous avez des raisons pour vos choix, et que je sois d'accord ou non avec ces choix, je respecte cela. Je ne sais pas exactement pourquoi, mais j'ai été sur une larme à propos de cette chose en particulier récemment (le -i en Perl sans suffixe). Je suis sûr que je trouverai bien assez tôt un autre sujet d'obsession :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X