web-dev-qa-db-fra.com

Comment remplacer une nouvelle ligne (\ n) avec sed?

Comment remplacer une nouvelle ligne ("\n") par un espace ("") à l'aide de la commande sed?

J'ai essayé sans succès:

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

Comment je le répare?

1255
hhh

Utilisez cette solution avec GNU sed:

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

Cela lira le fichier entier en boucle, puis remplacera la ou les nouvelles lignes par un espace.

Explication:

  1. Créez une étiquette via :a.
  2. Ajoutez la ligne en cours et la suivante à l'espace de répétition via N.
  3. Si nous sommes avant la dernière ligne, branchez sur l'étiquette créée $!ba ($! signifie ne pas le faire sur la dernière ligne car il devrait y avoir une dernière ligne).
  4. Enfin, la substitution remplace chaque nouvelle ligne par un espace sur l'espace de modèle (qui est le fichier entier).

Voici une syntaxe compatible entre plates-formes qui fonctionne avec BSD et OS X (sed (comme @ commentaire de Benjie ):

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

Comme vous pouvez le constater, utiliser sed pour résoudre ce problème, sinon simple, pose problème. Pour une solution plus simple et adéquate, voir cette réponse .

1411
Zsolt Botykai

Utilisez tr à la place?

tr '\n' ' ' < input_filename

ou supprimez entièrement les caractères de 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
1612
dmckee

Réponse rapide:

sed ':a;N;$!ba;s/\n/ /g' file
  1. : a crée une étiquette 'a'
  2. N ajoute la ligne suivante à l'espace de modèle
  3. $! si ce n'est la dernière ligne , ba branche (aller à) étiquette "a"
  4. s substitute , /\n / regex pour la nouvelle ligne , / / par un espace , / g correspondance globale (autant de fois que possible)

sed passe en boucle des étapes 1 à 3 jusqu’à la dernière ligne. Toutes les lignes s’insèrent dans l’espace du motif où sed remplace 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, sed - comme la vitesse

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

avec tr, plus rapide que sed , ne peut être remplacé que par un caractère

tr '\n' ' ' < file

avec paste, tr - comme la vitesse, ne peut être remplacé que par un caractère

paste -s -d ' ' file

avec awk, tr - comme la vitesse

awk 1 ORS=' ' file

Une autre alternative telle que "echo $ (<fichier)" est lente, ne fonctionne que sur de petits fichiers et doit traiter l’ensemble du fichier pour commencer le processus.


Réponse longue du sed FAQ 5.1 :

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

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

Sed fonctionne comme ceci: sed lit une ligne à la fois, coupe la
terminaison newline, place ce qui reste dans l’espace du motif où
le script sed peut l’adresser ou le changer, et quand le motif espace
est imprimé, ajoute une nouvelle ligne à stdout (ou à un fichier). Si la
l’espace du modèle est supprimé entièrement ou partiellement avec 'd' ou 'D',
nouvelle ligne est not 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 le retour à la ligne final est supprimé avant
la ligne est placée dans l’espace modèle. Pour effectuer les tâches ci-dessus,
utilisez plutôt l'un de ces scripts:

  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          

Depuis les versions de sed autres que GNU, _ sed ont des limites à la taille de
le tampon de motif, l’utilitaire Unix 'tr' doit être préféré ici.
Si la dernière ligne du fichier contient une nouvelle ligne, GNU sed ajoutera
cette nouvelle ligne à la sortie mais supprime toutes les autres, alors que tr sera
supprimer toutes les nouvelles lignes.

Pour faire correspondre un bloc de deux lignes ou plus, il existe 3 choix de base:
(1) utilisez la commande 'N' pour ajouter la ligne Next à l'espace du motif;
(2) utilisez la commande 'H' au moins deux fois pour ajouter 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 la 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é comme vous le souhaitez ('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 spécifique lignes consécutives?"). Cette
exemple peut être modifié en changeant la commande delete en quelque chose
sinon, comme 'p' (impression), 'i' (insérer), 'c' (changement), 'a' (annexe),
ou 's' (substitut).

Choice (3) ne mettra pas un\n dans l’espace du motif, mais il fait
correspond à un bloc de lignes consécutives, il se peut donc que vous ne le fassiez pas
a 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 '/ à partir d'ici /,/jusqu'à là/{...}'
adresses, il peut être possible d’éviter entièrement l’utilisation de\n.

455
hdorio

Une alternative awk plus courte:

awk 1 ORS=' '

Explication

Un programme awk est constitué de règles composé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 condition vraie et le 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 (séparateur d'enregistrement), qui est par défaut une nouvelle ligne. Ainsi, awk analysera par défaut la ligne d'entrée. sage. La scission implique également la suppression de RS de l'enregistrement d'entrée.

Désormais, lors de l'impression d'un enregistrement, ORS (séparateur d'enregistrement de sortie) y est ajouté. Par défaut, il s'agit à nouveau d'une nouvelle ligne. Donc, en changeant ORS en un espace, toutes les nouvelles lignes sont remplacées par des espaces.

212
Thor

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

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

La version Perl fonctionne comme 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 copie de sauvegarde du fichier original avant le remplacement si votre expression régulière n'était pas aussi intelligent que vous le pensiez.

84
ire_and_curses

Qui a besoin de sed? Voici le chemin bash:

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

Afin de remplacer toutes les nouvelles lignes par des espaces en utilisant awk, sans lire le fichier entier 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
24
Dennis Williamson
tr '\n' ' ' 

est la commande.

Simple et facile à utiliser.

21
Dheeraj R

Trois choses.

  1. tr (ou cat, etc.) n'est absolument pas nécessaire. (GNU) sed et (GNU) awk peuvent combiner 99,9% des traitements 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 sed lecture pour plus d'informations sur la différence. La plupart des gens confondent sed avec les lignes car il n’est pas très gourmand par défaut dans sa correspondance de motifs pour les correspondances SIMPLE - par exemple, lors de la recherche de motifs et le remplacement par un ou deux caractères, par défaut seulement remplace à la première correspondance trouvée (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 souhaitez effectuer une itération sur des lignes spécifiques (comme dans une boucle for), mais la plupart du temps, vous souhaiterez simplement sed.

  3. Cela étant dit,

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

    fonctionne très bien dans GNU sed version 4.2.1. 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 sécurité.

21
brent saner

La réponse avec le: une étiquette ...

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

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

 (echo foo; barre d'écho) | 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; écho bar) | 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.

12
Juan

Vous pouvez utiliser xargs :

seq 10 | xargs

ou

seq 10 | xargs echo -n
11
Vytenis Bivainis

Solution facile à comprendre

J'ai eu ce problème. Le kicker était que j'avais besoin de la solution pour fonctionner 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 une nouvelle ligne)

Il fonctionne sous Linux, OS X et BSD - même sans TF-8 ou avec un terminal de mauvaise qualité.

  1. Utilisez tr pour permuter la nouvelle ligne avec un autre caractère.

    NULL (\000 ou \x00) est agréable car il ne nécessite pas de prise en charge UTF-8 et il est peu probable qu'il soit utilisé.

  2. Utilisez sed pour faire correspondre le NULL

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

11
CoolAJ86

Je ne suis pas un expert, mais j'imagine que dans sed, vous devez d'abord ajouter la ligne suivante dans l'espace des motifs, en utilisant "N". Extrait de la section "Multiline Pattern Space" dans "Advanced sed Commands" du livre sed & awk (Dale Dougherty et Arnold Robbins; O'Reilly 1997; page 107 de aperç =):

La commande multiligne Next (N) crée un espace de modèle multiligne en lisant une nouvelle ligne d’entrée et en l’ajoutant au contenu de cet espace. Le contenu d'origine de l'espace modèle et la nouvelle ligne d'entrée sont séparés par une nouvelle ligne. Le caractère de nouvelle ligne incorporé peut être associé dans les modèles à 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 de modèle, et non au (x) caractère (s) suivant un ou des sauts de ligne incorporés. De même, "$" correspond uniquement à la nouvelle ligne finale dans l'espace modèle, et non à la ou aux nouvelles lignes intégrées. Une fois la commande Next exécutée, le contrôle est ensuite transmis aux commandes suivantes du script.

De man sed:

[2addr] N

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

J'ai tilisé ceci pour rechercher (plusieurs) fichiers journaux mal formatés, dans lesquels la chaîne de recherche peut être trouvée sur une ligne "orpheline".

9
Arjan

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

tr '\n' ' ' < input

ne fonctionnait pas pour moi, il s’agissait d’une erreur ou bien de remplacer le\n w/'' 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'

6
John Lawler

J'ai utilisé une approche hybride pour contourner le problème de la nouvelle ligne en utilisant tr pour remplacer les nouvelles lignes par des tabulations, puis en les remplaçant par ce que je voulais. Dans ce cas, "
"depuis que je tente de générer des sauts HTML.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`
6
rfengr

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 des scripts Shell réside dans le fait que si vous ne savez pas comment le faire d'une manière, vous pouvez le faire d'une autre manière. Et souvent, vous avez plus de choses à prendre en compte que de proposer une solution complexe à un problème simple.

En ce qui concerne le fait que gawk soit lent ... et lit le fichier en mémoire, je ne le sais pas, mais pour moi, gawk semble fonctionner avec une ligne à la fois et est très très rapide (pas si vite que certains autres , mais le temps nécessaire pour écrire et tester compte également).

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

5
mor

Solution anti-balles. Binary-data-safe et compatible POSIX, mais lent.

POSIX sed nécessite une entrée conformément aux définitions fichier texte POSIX et ligne POSIX , de sorte que les lignes NULL-octets et les lignes trop longues ne sont pas autorisées. doit se terminer par une nouvelle ligne (y compris la dernière ligne). Cela rend difficile l'utilisation de sed pour le traitement de données d'entrée arbitraires.

La solution suivante évite sed et convertit les octets d'entrée en codes octaux, puis à nouveau en octets, mais intercepte le code octal 012 (nouvelle ligne) et génère la chaîne de remplacement à la place. Autant que je sache, la solution est compatible POSIX et 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 '<br>\n' || printf "\\$x"; done

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

read, [ et printf sont tous deux intégrés à au moins bash, mais ce n'est probablement pas garanti par POSIX. Par conséquent, sur certaines plates-formes, chaque octet d'entrée commencera un ou plusieurs nouveaux processus, ce qui ralentira les choses. Même en bash, cette solution n'atteint que 50 ko/s environ, elle n'est donc pas adaptée aux fichiers volumineux.

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

5

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

Cependant, il y aurait des problèmes si votre entrée a un cas quelconque de unterminated quote, par ex. si les signes de citation sur une ligne donnée ne correspondent pas.

4
cnst

Si vous êtes assez malheureux pour vous occuper des fins de ligne Windows, vous devez supprimer le \r et le \n.

tr '[\r\n]' ' ' < $input > $output
4
StevenWernerCS

Trouve et remplace en utilisant\n

sed -ie -z 's/Marker\n/# Marker Comment\nMarker\n/g' myfile.txt

Marqueur

Devient

# Commentaire du marqueur

Marqueur

3
Proximo

Une solution que j’aime particulièrement est d’ajouter tout le fichier dans l’espace réservé et de remplacer toutes les nouvelles lignes à 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 limité dans certaines implémentations de sed.

3
brandizzi

Utiliser Awk:

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

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

Les solutions pures tr ne peuvent être remplacées que par un seul caractère et les solutions pures sed ne remplacent pas la dernière nouvelle ligne de l'entrée. La solution suivante résout ces problèmes et semble sans danger pour les données binaires (même avec les paramètres régionaux UTF-8):

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

Résultat:

1<br>2<br>3<br>
3
Håkon A. Hjortland

C'est sed qui introduit les nouvelles lignes après la substitution "normale". Tout d'abord, il supprime le caractère de nouvelle ligne, puis il traite conformément à vos instructions, puis il introduit une nouvelle ligne.

En utilisant sed, vous pouvez remplacer "la fin" d'une ligne (et non du caractère new-line) après avoir été coupé, par une chaîne de votre choix, pour chaque ligne en entrée; mais, sed affichera des lignes différentes. Par exemple, supposons que vous vouliez remplacer le "fin de ligne" par "===" (plus général qu'un remplacement par un seul espace):

Prompt~$ cat <<EOF |sed 's/$/===/g'
first line
second line
3rd line
EOF

first line===
second line===
3rd line===
Prompt~$

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

Par exemple:

Prompt~$ cat <<EOF | tr '\n' $'\x01'|sed -e 's/\x01/===/g'
first line
second line
3rd line
EOF

first line===second line===3rd line===Prompt~$
3
Robert Vila

Pour supprimer les lignes vides:

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

Une autre méthode GNUsed, presque identique à (Zsolt Botykai ) = = =, mais ceci utilise la commande sed ( transliterate ) de y moins fréquemment utilisée, qui enregistre un octet de code (le g final):

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

On peut espérer que y sera plus rapide que s, (peut-être à tr vitesses 20 fois plus vite), mais en GNU sed v4.2.2 y est environ 4% plus lent que s.


Plus portable BSDsed version:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
3
agc

Sur Mac OS X (avec 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
3
bashfu

Vous pouvez aussi utiliser cette méthode

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.

Couler:
Lorsque la première ligne sort de l’entrée, l’échange est fait, alors 1 va mettre un espace et\n va dans l’espace du motif, puis ajoute l’espace de maintien à l’espace du motif, puis la substitution est effectuée et le motif est supprimé espace.
Au cours de la deuxième ligne, l’échange est effectué, 2 vont pour maintenir l’espace et 1 pour entrer pour les motifs, puis G ajoutera l’espace de maintien dans l’espace pour les motifs, puis h copiera le motif pour et la substitution est faite et supprimée. Cette opération est poursuivie jusqu'à ce que eof soit atteint, puis le résultat exact est imprimé.

2
Kalanidhi

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

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

Cela ne fonctionne pas pour les gros fichiers (limite de mémoire tampon), mais il est très efficace s'il y a assez de mémoire pour contenir le fichier. (Correction H-> 1h;1!H après la bonne remarque de @hilojack)

Une autre version qui change de nouvelle ligne en lisant (plus de cpu, moins de mémoire)

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

J'ai posté cette réponse parce que j'ai essayé avec la plupart des exemples de sedgend fournis ci-dessus, qui ne fonctionnent pas pour moi dans ma boîte Unix et qui me donnent le message d'erreur Label too long: {:q;N;s/\n/ /g;t q}. Enfin, j'ai fait mon exigence et donc partagé ici qui fonctionne dans tous les environnements Unix/Linux: -

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

La première ligne supprimera toute la nouvelle ligne du fichier yoursourcefile.txt et produira une seule ligne. Et la seconde commande sed en supprimera tous les espaces.

1

Vous pouvez également utiliser le Editeur de texte standard :

printf '%s\n%s\n%s\n' '%s/$/ /' '%j' 'w' | ed -s file

Remarque: cela enregistre le résultat dans file.

Comme avec sed, cette solution doit d'abord charger tout le fichier en mémoire.

0
Thor

Cela pourrait fonctionner pour vous (GNU sed):

sed 'H;$!d;x;:a;s/^((.).*)\2/\1 /;ta;s/.//' file

La commande H ajoute une nouvelle ligne à l'espace modèle, puis ajoute le résultat à l'espace d'attente. Le flux normal de sed consiste à supprimer la nouvelle ligne suivante de chaque ligne, ce qui introduira une nouvelle ligne au début de l'espace de maintien et à la réplication du reste du fichier. Une fois que le fichier a été inséré dans l’espace de blocage, remplacez-le par l’espace de blocage, puis utilisez la correspondance de motif pour remplacer toutes les lignes nouvelles originales par des espaces. Enfin, supprimez la nouvelle ligne introduite.

Cela a l’avantage de ne jamais entrer réellement de chaîne de nouvelle ligne dans les commandes sed.

0
potong