Comment puis-je remplacer une nouvelle ligne (\ n) par sed?

Comment puis-je remplacer une nouvelle ligne ( \n ) par la commande sed?

J’ai essayé sans succès:

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

Comment je le répare?

Utilisez cette solution avec GNU sed :

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

Ceci lira le fichier entier dans une boucle, puis remplacera la ou les nouvelles lignes par un espace.

Explication:

  1. Créez une étiquette via :a .
  2. Ajoutez la ligne actuelle et la ligne suivante à l’espace du motif via N
  3. Si nous sums avant la dernière ligne, connectez-vous à l’étiquette $!ba ( $! Signifie ne pas le faire sur la dernière ligne car il devrait y avoir une nouvelle ligne finale).
  4. Enfin, la substitution remplace chaque nouvelle ligne par un espace dans l’espace du motif (qui est le fichier entier).

Voici une syntaxe compatible avec plusieurs plates-formes qui fonctionne avec le sed BSD et OS X (selon le commentaire @Benjie ):

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

Utilisez tr place?

 tr '\n' ' ' < input_filename 

ou supprimez entièrement les caractères de la nouvelle ligne:

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

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

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

Réponse rapide:

 sed ':a;N;$!ba;s/\n/ /g' file 
  1. : a créer une étiquette ‘a’
  2. N ajoute la ligne suivante à l’espace du motif
  3. $! sinon la dernière ligne , ba twigz (allez à) étiquette ‘a’
  4. s substitue , / \ n / regex pour une nouvelle ligne , / / par un espace , / g correspondance globale (autant de fois que possible)

sed passera par les étapes 1 à 3 jusqu’à ce qu’elle atteigne la dernière ligne, obtenant toutes les lignes dans l’espace du motif où sed remplacera tous les caractères \ n


Alternatives :

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

avec bash , lent

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

avec perl , vitesse de type sed

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

avec tr , plus rapide que sed , peut remplacer par un seul caractère

 tr '\n' ' ' < file 

avec coller , vitesse tr- like, peut remplacer par un seul caractère

 paste -s -d ' ' file 

avec awk , la vitesse tr- like

 awk 1 ORS=' ' file 

Une autre alternative comme "echo $ ( est lente, ne fonctionne que sur de petits fichiers et doit traiter tout le fichier pour commencer le processus.


Réponse longue de la FAQ sed 5.10 :

5.10. Pourquoi ne puis-je pas associer ou supprimer une nouvelle ligne à l'aide de la fuite \ n
séquence? Pourquoi ne puis-je pas faire correspondre 2 lignes ou plus en utilisant \ n?

Le \ n ne correspondra jamais à la nouvelle ligne en fin de ligne car le
newline est toujours enlevé avant que la ligne soit placée dans le
espace de motif. Pour obtenir 2 lignes ou plus dans l’espace du motif, utilisez
la commande 'N' ou quelque chose de similaire (tel que 'H; ...; g;').

Sed fonctionne comme ceci: sed lit une ligne à la fois, coupe la
terminaison newline, met ce qui rest dans l’espace du motif où
le script sed peut l’adresser ou le modifier, et quand l’espace du motif
est imprimé, ajoute une nouvelle ligne à stdout (ou à un fichier). Si la
L'espace du motif est entièrement ou partiellement supprimé avec «d» ou «D», le
newline n'est pas ajouté 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 avant
la ligne est placée dans l'espace de motif. 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 

Puisque les versions de sed autres que GNU sed ont des limites à la taille de
le tampon de modèle, l'utilitaire Unix 'tr' doit être préféré ici.
Si la dernière ligne du fichier contient une nouvelle ligne, GNU sed appenda
que newline à la sortie mais supprimez tous les autres, alors que tr va
supprimer toutes les nouvelles lignes.

Pour faire correspondre un bloc de deux lignes ou plus, il y a 3 choix de base:
(1) utiliser la commande 'N' pour append la ligne Next à l’espace du pattern;
(2) utiliser la commande 'H' au moins deux fois pour append la ligne en cours
dans l'espace d'attente, puis récupérez les lignes de l'espace d'attente
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) placeront un \ n dans l’espace du motif, où
peut être adressé à volonté ('s / ABC \ nXYZ / alphabet / g'). Un exemple
d'utiliser 'N' pour supprimer un bloc de lignes apparaît dans la section 4.13
("Comment supprimer un bloc de lignes consécutives spécifiques ?"). Ce
exemple peut être modifié en changeant la commande de suppression à quelque chose
autrement, comme 'p' (print), 'i' (insert), 'c' (change), 'a' (append),
ou 's' (substitut).

Le choix (3) ne mettra pas un \ n dans l’espace du motif, mais
faire correspondre un bloc de lignes consécutives, il se peut donc que vous n'ayez pas
même besoin de \ n pour trouver ce que vous cherchez. Depuis GNU sed
la version 3.02.80 supporte maintenant cette syntaxe:

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

en plus de la gamme traditionnelle '/ from here /, / to there / {...}'
adresses, il peut être possible d'éviter l'utilisation de \ n entièrement.

Une alternative plus courte:

 awk 1 ORS=' ' 

Explication

Un programme awk est constitué de règles constituées de blocs de code conditionnels, à savoir:

 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 vraie condition et print $0 est exécuté pour chaque ligne.

Lorsque awk lit l’entrée, il la divise en enregistrements en fonction de la valeur de RS (Record Separator), qui est par défaut une nouvelle ligne. Ainsi, awk parsingra par défaut la ligne en entrée. Le fractionnement implique également la suppression de RS de l’enregistrement d’entrée.

Maintenant, lors de l’impression d’un enregistrement, ORS (Output Record Separator) lui est ajouté (la valeur par défaut est une nouvelle ligne). Donc, en changeant ORS à un espace, toutes les nouvelles lignes sont remplacées par des espaces.

gnu sed a une option -z pour les enregistrements séparés par des lignes (lignes). Vous pouvez simplement appeler:

 sed -z 's/\n/ /g' 

La version Perl fonctionne comme prévu.

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

Comme indiqué dans les commentaires, il convient de noter que ces modifications sont en place. -i.bak vous donnera une sauvegarde du fichier original avant le remplacement au cas où votre expression régulière ne serait pas aussi intelligente que vous le pensiez.

Qui a besoin de sed ? Voici la manière de bash :

 cat test.txt | while read line; do echo -n "$line "; done 

Afin de remplacer toutes les nouvelles lignes par des espaces en utilisant awk, sans lire tout le fichier en mémoire:

 awk '{printf "%s ", $0}' inputfile 

Si vous voulez une nouvelle ligne finale:

 awk '{printf "%s ", $0} END {printf "\n"}' inputfile 

Vous pouvez utiliser un caractère autre que l’espace:

 awk '{printf "%s|", $0} END {printf "\n"}' inputfile 

Trois choses.

  1. tr (ou cat , etc.) n’est absolument pas nécessaire. (GNU) sed et (GNU) awk , lorsqu’ils sont combinés, peuvent effectuer 99,9% de tout traitement de texte dont vous avez besoin.

  2. stream! = basé sur la ligne. ed est un éditeur basé sur des lignes. sed n’est pas. Voir le cours sed pour plus d’informations sur la différence. La plupart des gens confondent sed avec line car il est, par défaut, peu gourmand en correspondance de modèle pour les correspondances SIMPLE – par exemple, lors de la recherche de motif et du remplacement par un ou deux caractères, il ne remplace par défaut que le premier correspond à ce qu’il trouve (sauf indication contraire de la commande globale). Il n’y aurait même pas de commande globale si elle était basée sur les lignes plutôt que sur STREAM, car elle n’évaluerait que les lignes à la fois. Essayez de lancer ed ; vous remarquerez la différence. ed est très utile si vous voulez effectuer une itération sur des lignes spécifiques (comme dans une boucle for), mais la plupart du temps, vous voudrez juste sed .

  3. Cela étant dit,

     sed -e '{:q;N;s/\n/ /g;tq}' file 

    fonctionne correctement dans la version 4.2.1 de GNU sed . La commande ci-dessus remplacera toutes les nouvelles lignes par des espaces. C’est moche et un peu lourd à taper, mais ça marche très bien. Les {} peuvent être omis, car ils ne sont inclus que pour des raisons de santé mentale.

 tr '\n' ' ' 

est la commande.

Simple et facile à utiliser.

La réponse à la: une étiquette …

Comment puis-je remplacer une nouvelle ligne (\ n) par sed?

… ne fonctionne pas dans freebsd 7.2 sur la ligne de commande:

 (echo foo; echo bar) |  sed ': a; N; $! ba; s / \ n / / g'
 sed: 1: ": a; N; $! ba; s / \ n / / g": étiquette inutilisée 'a; N; $! ba; s / \ n / / g'
 foo
 bar

Mais si vous mettez le script sed dans un fichier ou utilisez -e pour “construire” le script sed …

 > (echo foo; barre d'écho) |  sed -e: a -e N -e '$! ba' -e s / \ n / / g '
 foo bar

ou …

 > cat > x.sed < < eof :a N $!ba s/\n/ /g eof > (echo foo; echo bar) | sed -f x.sed foo bar 

Peut-être que le sed dans OS X est similaire.

Vous pouvez utiliser xargs :

 seq 10 | xargs 

ou

 seq 10 | xargs echo -n 

Je ne suis pas un expert, mais je suppose que dans un premier temps, vous devez d’abord append la ligne suivante dans l’espace des motifs, en utilisant ” N “. Dans la section “Espace modèle multiligne” dans “Commandes sed avancées” du livre sed & awk (Dale Dougherty et Arnold Robbins; O’Reilly 1997; page 107 dans l’aperçu ):

La commande Next (N) multiligne crée un espace de modèle multiligne en lisant une nouvelle ligne d’entrée et en l’ajoutant au contenu de l’espace de modèle. Le contenu d’origine de l’espace object et la nouvelle ligne d’entrée sont séparés par une nouvelle ligne. Le caractère de nouvelle ligne incorporé peut être mis en correspondance dans les modèles par la séquence d’échappement “\ n”. Dans un espace de modèle multiligne, le métacaractère “^” correspond au tout premier caractère de l’espace du modèle, et non au (x) caractère (s) suivant toute nouvelle ligne incorporée. De même, “$” correspond uniquement à la nouvelle ligne finale dans l’espace du modèle, et non à une ou plusieurs nouvelles lignes intégrées. Une fois la commande Next exécutée, le contrôle est transmis aux commandes suivantes du script.

De man sed :

[2addr] N

Ajoutez la ligne d’entrée suivante à l’espace object, en utilisant un caractère de nouvelle ligne incorporé pour séparer le matériau ajouté du contenu d’origine. Notez que le numéro de ligne actuel change.

Je l’ai utilisé pour rechercher (plusieurs) fichiers journaux mal formatés, dans lesquels la chaîne de recherche peut être trouvée sur une ligne suivante “orpheline”.

Solution facile à comprendre

J’ai eu ce problème. Le kicker était que j’avais besoin de la solution pour travailler sur BSD (Mac OS X) et GNU (Linux et Cygwin ) sed et tr :

 $ echo 'foo bar baz foo2 bar2 baz2' \ | tr '\n' '\000' \ | sed 's:\x00\x00.*:\n:g' \ | tr '\000' '\n' 

Sortie:

 foo bar baz 

(a nouvelle ligne de fuite)

Il fonctionne sous Linux, OS X et BSD – même sans support UTF-8 ou avec un terminal minable.

  1. Utilisez tr pour échanger la nouvelle ligne avec un autre personnage.

    NULL ( \000 ou \x00 ) est intéressant car il ne nécessite pas de support UTF-8 et il est peu probable qu’il soit utilisé.

  2. Utilisez sed pour correspondre à la NULL

  3. Utilisez tr pour échanger des lignes supplémentaires si vous en avez besoin

En réponse à la solution “tr” ci-dessus, sous Windows (probablement en utilisant la version Gnuwin32 de tr), la solution proposée:

 tr '\n' ' ' < input 

ne fonctionnait pas pour moi, il y avait soit erreur soit réellement remplacer le \ nw / '' pour une raison quelconque.

En utilisant une autre fonctionnalité de tr, l'option "delete" -d fonctionnait bien:

 tr -d '\n' < input 

ou '\ r \ n' au lieu de '\ n'

J’ai utilisé une approche hybride pour contourner la nouveauté en utilisant tr pour remplacer les nouvelles lignes par des tabulations, puis en remplaçant les tabulations par ce que je voulais. Dans ce cas, ”
“depuis que j’essaye de générer des ruptures HTML.

 echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ 
/g'`

Dans certaines situations, vous pouvez peut-être remplacer RS par une autre chaîne ou un autre caractère. De cette façon, \ n est disponible pour sub / gsub:

 $ gawk 'BEGIN {RS="dn" } {gsub("\n"," ") ;print $0 }' file 

La puissance du script shell est que si vous ne savez pas comment le faire d’une manière, vous pouvez le faire d’une autre manière. Et plusieurs fois, vous avez plus de choses à prendre en compte que de faire une solution complexe à un problème simple.

En ce qui concerne le fait que gawk est lent … et lit le fichier en mémoire, je ne le sais pas, mais pour moi, gawk semble fonctionner avec une seule ligne à la fois et est très très rapide (pas aussi rapide que certaines des autres) , mais le temps pour écrire et tester compte aussi.

Je traite des Mo et même des Go de données, et la seule limite que j’ai trouvée est la taille de la ligne.

Vous pouvez utiliser xargs – il remplacera \n par un espace par défaut.

Cependant, il y aurait des problèmes si votre entrée unterminated quote , par exemple si les guillemets d’une ligne donnée ne correspondent pas.

Solution à l’épreuve des balles. Binary-data-safe et compatible POSIX, mais lent.

POSIX sed nécessite une entrée en fonction du fichier texte POSIX et des définitions de ligne POSIX , de sorte que les octets NULL et les lignes trop longues ne sont pas autorisés et chaque ligne doit se terminer par une nouvelle ligne (y compris la dernière ligne). Cela rend difficile l’utilisation de sed pour traiter des données d’entrée arbitraires.

La solution suivante évite sed et convertit à la place les octets d’entrée en codes octaux, puis les octets à nouveau, mais intercepte le code octal 012 (newline) et affiche la chaîne de remplacement à la place. Pour autant que je sache, la solution est compatible avec POSIX, elle devrait donc fonctionner sur une grande variété de plates-formes.

 od -A n -t o1 -v | tr ' \t' '\n\n' | grep . | while read x; do [ "0$x" -eq 012 ] && printf '
\n' || printf "\\$x"; done

Documentation de référence POSIX: sh , langage de commande shell , od , tr , grep , read , [ , printf .

read , [ et printf sont tous deux intégrés dans au moins bash, mais cela n’est probablement pas garanti par POSIX. Sur certaines plates-formes, il se peut que chaque octet d’entrée lance un ou plusieurs nouveaux processus, ce qui ralentit les choses. Même dans le cas de bash, cette solution n’atteint que 50 Ko / s, elle n’est donc pas adaptée aux gros fichiers.

Testé sur Ubuntu (bash, dash et busybox), FreeBSD et OpenBSD.

Sur Mac OS X (en utilisant FreeBSD sed):

 # replace each newline with a space printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g; ta' printf "a\nb\nc\nd\ne\nf" | sed -E -e :a -e '$!N; s/\n/ /g' -e ta 

En utilisant Awk:

 awk "BEGIN { o=\"\" } { o=o \" \" \$0 } END { print o; }" 

Une solution que j’aime particulièrement consiste à append tous les fichiers dans l’espace d’attente et à remplacer tous les nouveaux traits à la fin du fichier:

 $ (echo foo; echo bar) | sed -n 'H;${x;s/\n//g;p;}' foobar 

Cependant, quelqu’un m’a dit que l’espace d’attente peut être fini dans certaines implémentations sed.

Remplacez les nouvelles lignes par n’importe quelle chaîne et remplacez également la dernière ligne

Les solutions tr pure ne peuvent remplacer que par un seul caractère, et les solutions sed pure ne remplacent pas la dernière ligne de saisie de l’entrée. La solution suivante résout ces problèmes et semble être sûre pour les données binarys (même avec un environnement local UTF-8):

 printf '1\n2\n3\n' | sed 's/%/%p/g;s/@/%a/g' | tr '\n' @ | sed 's/@/
/g;s/%a/@/g;s/%p/%/g'

Résultat:

 1
2
3

C’est sed qui introduit les nouvelles lignes après une substitution “normale”. D’abord, il coupe le caractère de nouvelle ligne, puis il traite selon vos instructions, puis il introduit une nouvelle ligne.

En utilisant sed, vous pouvez remplacer “la fin” d’une ligne (pas le caractère de nouvelle ligne) après avoir été rogné, avec une chaîne de votre choix, pour chaque ligne d’entrée; mais sed affichera différentes lignes. Par exemple, supposons que vous vouliez remplacer “end of line” par “===” (plus général qu’un remplacement par un seul espace):

 PROMPT~$ cat <  

Pour remplacer le caractère de nouvelle ligne par la chaîne, vous pouvez, de manière inefficace, utiliser tr , comme indiqué précédemment, pour remplacer les caractères de nouvelle ligne par un "caractère spécial", puis utiliser sed pour remplacer ce caractère par la chaîne souhaitée. .

Par exemple:

 PROMPT~$ cat <  

@OP, si vous voulez remplacer les nouvelles lignes dans un fichier, vous pouvez simplement utiliser dos2unix (ou unix2dox)

 dos2unix yourfile yourfile 

Pour supprimer les lignes vides:

 sed -n "s/^$//;t;p;" 

You can use this method also

 sed 'x;G;1!h;s/\n/ /g;$!d' 

Explication

 x - which is used to exchange the data from both space (pattern and hold). G - which is used to append the data from hold space to pattern space. h - which is used to copy the pattern space to hold space. 1!h - During first line won't copy pattern space to hold space due to \n is available in pattern space. $!d - Clear the pattern space every time before getting next line until the last line. 

Flow:
When the first line get from the input, exchange is made, so 1 goes to hold space and \n comes to pattern space, then appending the hold space to pattern space, and then substitution is performed and deleted the pattern space.
During the second line exchange is made, 2 goes to hold space and 1 comes to pattern space, then G append the hold space into the pattern space, then h copy the pattern to it and substitution is made and deleted. This operation is continued until eof is reached then print exact result.

Another sed method, almost the same as Zsolt Botykai ‘s answer , but this uses sed ‘s less-frequently used y ( transliterate ) command, which saves one byte of code (the trailing g ):

 sed ':a;N;$!ba;y/\n/ /' 

One would hope y would run faster than s , (perhaps at tr speeds, 20x faster), but in GNU sed v4.2.2 y is about 4% slower than s .

 sed '1h;1!H;$!d x;s/\n/ /g' YourFile 

This does not work for huge files (buffer limit), but it is very efficient if there is enough memory to hold the file. (Correction H -> 1h;1!H after the good remark of @hilojack )

Another version that change new line while reading (more cpu, less memory)

  sed ':loop $! N s/\n/ / t loop' YourFile 

I posted this answer because I have sortinged with most of the sed commend example provided above which does not work for me in my Unix box and giving me error message Label too long: {:q;N;s/\n/ /g;tq} . Finally I made my requirement and hence shared here which works in all Unix/Linux environment:-

 line=$(while read line; do echo -n "$line "; done < yoursourcefile.txt) echo $line |sed 's/ //g' > sortedoutput.txt 

The first line will remove all the new line from file yoursourcefile.txt and will produce a single line. And second sed command will remove all the spaces from it.