Comment puis-je remplacer une nouvelle ligne (n) en utilisant sed?

Comment remplacer une nouvelle ligne ( n ) en utilisant la commande sed?

j'ai essayé sans succès:

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

Comment puis-je le réparer?

1156
sed
demandé sur Eliran Malka 2009-08-09 23:10:10

30 réponses

utilisez cette solution avec GNU sed :

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

ceci Lira le fichier entier en boucle, puis remplacera la(les) Nouvelle (S) Ligne (s) par un espace.

explication:

  1. créer une étiquette via :a .
  2. ajoute la ligne courante et la ligne suivante à l'espace de motif via N .
  3. si nous sommes avant la dernière ligne, branche au label créé $!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 ligne par un espace sur l'espace de motif (qui est le fichier entier).

Voici la syntaxe compatible multiplateforme qui fonctionne avec sed de BSD et OS X (selon @Benjie comment ):

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

comme vous pouvez le voir, en utilisant sed pour ce problème par ailleurs simple est problématique. Pour une solution plus simple et adéquate voir cette réponse .

1298
répondu Zsolt Botykai 2018-09-23 17:56:14

utilisez tr à la place?

tr '\n' ' ' < input_filename

ou supprimer entièrement les caractères newline:

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
1475
répondu dmckee 2017-06-05 12:05:40

réponse rapide:

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

sed fera une boucle à travers les étapes 1 à 3 jusqu'à ce qu'il atteigne la dernière ligne, obtenir toutes les lignes l'espace de motif où sed remplacera tous les caractères \n


variantes :

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

avec bash , lente

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 le sed , peut remplacer par un seul caractère

tr '\n' ' ' < file

avec coller , tr comme la vitesse, peut les remplacer par un seul caractère

paste -s -d ' ' file

avec awk , tr de la vitesse

awk 1 ORS=' ' file

autres alternative comme "echo $(< file)" est lente, ne fonctionne que sur les petits fichiers et a besoin de traiter l'ensemble du fichier pour commencer le processus.


longue réponse de la sed FAQ 5.10 :

5.10. Pourquoi ne puis-je pas faire correspondre ou supprimer une nouvelle ligne en utilisant le \ N escape

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 retiré avant que la ligne soit placée dans le

modèle de l'espace. Pour obtenir 2 ou plusieurs lignes dans l'espace modèle, utilisez

la commande ' N 'ou quelque chose de similaire (comme' H;...;g.)';

sed fonctionne comme ceci: sed lit une ligne à la fois, Coupe le

finissant newline, met ce qui reste dans l'espace de motif où

le script sed peut l'adresser ou le changer, et lorsque l'espace de motif

est imprimé, ajoute une nouvelle ligne à stdout (ou à un fichier). Si le

l'espace de dessin est entièrement ou partiellement supprimé par " d " ou "D", Le

newline est pas ajouté dans tel 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, parce que la nouvelle ligne arrière est enlevée avant

la ligne est placée dans l'espace de motif. Pour accomplir les tâches ci-dessus,

utilisez 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 de taille de

le tampon de pattern, 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 supprimer tous les autres, tandis que tr sera

supprimer toutes les nouvelles lignes.

pour correspondre à un bloc de deux lignes ou plus, il ya 3 de base choix:

(1) Utilisez la commande 'N' pour ajouter la ligne suivante à l'espace de motif;

(2) Utilisez la commande' H 'au moins deux fois pour ajouter la ligne courante

à l'espace de cale, puis récupérer les lignes de l'espace de cale

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.

Choices (1) et (2) mettra un \n dans l'espace modèle, où il

peut être adressée 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 puis-je supprimer un bloc de spécifique lignes consécutives?"). Ce

exemple peut être modifié par changer la commande Supprimer en quelque chose

autrement, comme "p" (en lettres moulées), "i" (en lettres moulées), "c" (en lettres moulées), " a "(en lettres moulées),

ou 's' (suppléant).

choix (3) ne mettra pas un \n dans l'espace de modèle, mais il fait

correspondent à un bloc de lignes consécutives, il se peut donc que vous ne

même besoin de l' \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 du traditionnel " / d'ici/, / à là / {...}' de la gamme

les adresses, il peut être possible d'éviter l'utilisation de \n entièrement.

418
répondu hdorio 2013-09-26 12:41:58

Une courte awk alternative:

awk 1 ORS=' '

explication

un programme awk est construit de règles qui consistent en des blocs de code conditionnels, i.e.:

condition { code-block }

si le bloc de code est omis, la valeur par défaut est { print " 151920920" } . Ainsi, le 1 est interprété comme une condition vraie et le print " 151940920 " est exécuté pour chaque ligne.

quand awk lit l'entrée qu'il divise il est utilisé dans les enregistrements basés sur la valeur de RS (séparateur D'enregistrement), qui par défaut est une nouvelle ligne, donc awk analysera par défaut la ligne d'entrée. Le fractionnement consiste également à enlever RS de l'enregistrement d'entrée.

maintenant, lors de l'impression d'un enregistrement, ORS (séparateur D'enregistrement de sortie) est ajouté à celui-ci, la valeur par défaut est une nouvelle ligne. Ainsi, en remplaçant ORS par un espace, toutes les lignes sont changées en espaces.

180
répondu Thor 2018-10-02 13:00:41

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

sed -z 's/\n/ /g'
99
répondu JJoao 2018-03-16 10:05:25

la version Perl fonctionne comme prévu.

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

comme il est souligné dans les commentaires, il est intéressant de noter que ces modifications sont en place. -i.bak vous donnera une sauvegarde du fichier original avant le remplacement dans le cas où votre expression régulière n'est pas aussi intelligent que vous le pensiez.

77
répondu ire_and_curses 2015-03-31 08:09:34

qui a besoin de sed ? Voici le bash chemin:

cat test.txt |  while read line; do echo -n "$line "; done
41
répondu commonpike 2014-08-08 09:27:18

afin de remplacer toutes les nouvelles lignes par des espaces utilisant awk, sans lire l'ensemble du fichier en mémoire:

awk '{printf "%s ", "151900920"}' inputfile

Si vous voulez un dernier retour à la ligne:

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

vous pouvez utiliser un caractère autre que l'espace:

awk '{printf "%s|", "151920920"} END {printf "\n"}' inputfile
24
répondu Dennis Williamson 2012-03-30 06:41:01

trois choses.

  1. tr (ou cat , etc.) n'est absolument pas nécessaire. (GNU) sed et (GNU) awk , une fois combinés, peuvent faire 99,9% de tout traitement de texte dont vous avez besoin.

  2. stream != ligne de base. ed est un éditeur de lignes. sed n'est pas. Voir sed conférence pour plus d'informations sur la différence. La plupart des gens confondent sed doit être basé sur la ligne parce qu'il n'est pas, par défaut, très gourmand en ce qui concerne l'appariement de modèles pour les correspondances simples-par exemple, lors de la recherche de modèles et de leur remplacement par un ou deux caractères, il ne remplace par défaut que la première correspondance qu'il trouve (sauf indication contraire par 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 les flux, car elle n'évaluerait que les lignes à la fois. Essayez ed ; vous remarquerez le différence. ed est assez utile si vous voulez itérer sur des lignes spécifiques (comme dans une boucle for), mais la plupart du temps vous voulez juste sed .

  3. cela 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 encombrant à taper, mais ça marche très bien. Le {} 's peut être exclu, comme ils ne sont inclus que pour des raisons de santé mentale.

20
répondu brent saner 2015-07-01 15:15:28
tr '\n' ' ' 

est la commande.

Simple et facile à utiliser.

18
répondu Dheeraj R 2014-05-01 13:54:56

La réponse avec l' :un label ...

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

... ne fonctionne pas sous freebsd 7.2 en ligne de commande:

( echo foo ; echo bar ) | sed ':a;N;$!ba;s/\n/ /g'
sed: 1: ":a;N;$!ba;s/\n/ /g": unused label 'a;N;$!ba;s/\n/ /g'
foo
bar

Mais si vous mettez le script sed dans un fichier ou utilisez -e à "construire" le script sed...

> (echo foo; echo 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
répondu Juan 2017-05-23 12:18:33

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

la commande multiline Next (N) crée un espace de motif multiligne en lisant un nouvelle ligne d'entrée et d'ajouter du contenu du modèle de l'espace. Le contenu original de pattern space et la nouvelle ligne d'entrée sont séparés par une nouvelle ligne. Le caractère newline intégré peut être apparié dans les motifs par la séquence d'échappement "\n". Dans un espace de motifs multilignes, le metacharacter "^" correspond au tout premier caractère de l'espace de motifs, et non au(X) caractère(s) suivant une (des) nouvelle (s) ligne (S) intégrée (s). De même, " $ " ne correspond qu'à la dernière ligne dans l'espace pattern, et aucune intégré de saut de ligne(s). Après l'exécution de la commande suivante, le contrôle est transmis aux commandes suivantes dans le script.

de man sed :

[2addr]N

ajouter la ligne suivante à l'espace de dessin, en utilisant un caractère newline intégré pour séparer le matériel ajouté du contenu original. Notez que le numéro de ligne actuel change.

J'ai utilisé ce pour rechercher des fichiers journaux (multiples) mal formatés, dans lesquels la chaîne de recherche peut être trouvée sur une ligne" orphelin " suivante.

9
répondu Arjan 2017-05-23 10:31:36

solution facile à comprendre

j'ai eu ce problème. Le problème é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' '"151900920"0' \
| sed 's:\x00\x00.*:\n:g' \
| tr '"151900920"0' '\n'

sortie:

foo
bar
baz

(a fuite saut de ligne)

il fonctionne sur Linux, OS X, et BSD - même sans UTF-8 support ou avec un terminal merdique.

  1. utilisez tr pour échanger la nouvelle ligne avec un autre caractère.

    NULL ( "151960920"0 ou \x00 ) est agréable parce qu'il n'a pas besoin de support UTF-8 et qu'il n'est pas susceptible d'être utilisé.

  2. "utiliser sed pour correspondre au NULL

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

9
répondu CoolAJ86 2015-03-31 16:33:04

vous pouvez utiliser xargs :

seq 10 | xargs

ou

seq 10 | xargs echo -n
9
répondu Vytenis Bivainis 2015-03-31 16:38:16

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

tr '\n' ' ' < input

ne fonctionnait pas pour moi, il aurait soit erreur ou réellement remplacer le \N w/ " pour une raison quelconque.

en utilisant une autre caractéristique de tr, l'option "delete" - d a fonctionné cependant:

tr -d '\n' < input

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

6
répondu John Lawler 2011-02-25 22:54:36

j'ai utilisé une approche hybride pour contourner le truc de la newline en utilisant tr Pour remplacer les newlines par des onglets, puis en remplaçant les onglets par ce que je veux. Dans ce cas, "

" depuis que j'essaie de générer des bris HTML.

echo -e "a\nb\nc\n" |tr '\n' '\t' | sed 's/\t/ <br> /g'`
6
répondu rfengr 2015-03-31 16:33:35

à l'épreuve des balles solution. Binaire-données-sûr et POSIX-conforme, mais lent.

POSIX sed nécessite une entrée en fonction de la fichier texte POSIX et POSIX line définitions, donc NULL-bytes 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). Il est donc difficile d'utiliser sed pour traiter des données d'entrée arbitraires.

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

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 , shell de commande de la langue , od , tr , grep , lire , [ , printf .

les deux read , [ , et printf sont intégrés dans au moins bash, mais ce n'est probablement pas garanti par POSIX, donc sur certaines plateformes il se peut que chaque octet d'entrée démarre un ou plusieurs nouveaux processus, ce qui ralentira les choses. Même à bash cette solution atteint seulement environ 50 kB / s, donc ce n'est pas fait pour les gros dossiers.

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

5
répondu Håkon A. Hjortland 2014-04-19 06:15:37

dans certaines situations, vous pouvez peut-être changer RS en 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 "151900920" }' file

le pouvoir des scripts 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 souvent vous avez plus de choses à prendre en compte que de faire une solution complexe sur un problème simple.

à propos de la chose que gawk est lent... et lit le fichier dans de mémoire, je ne sais pas, mais pour moi, gawk semble fonctionner avec une ligne à la fois et il est très très rapide (pas si rapide que les autres, mais le temps d'écrire et de tester compte aussi).

je traite MB et même GB de données, et la seule limite que j'ai trouvé est la taille de la ligne.

5
répondu mor 2016-01-05 08:31:13

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

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

4
répondu cnst 2013-03-28 15:06:25

sur Mac OS X (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
3
répondu bashfu 2010-07-28 10:44:38

Utilisant Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" $0 }  END { print o; }"
3
répondu kralyk 2011-06-06 15:15:45

une solution que j'aime particulièrement est d'ajouter tout le fichier dans l'espace d'attente 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 sed.

3
répondu brandizzi 2011-07-13 14:35:10

remplacer newlines par any string, et remplacer la dernière newline too

les solutions pures tr ne peuvent remplacer qu'avec un seul caractère, et les solutions pures sed ne remplacent pas la dernière ligne d'entrée. La solution suivante corrige ces problèmes, et semble être sûre pour les données binaires (même avec une locale 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
répondu Håkon A. Hjortland 2013-02-26 14:15:01

c'est sed qui introduit les nouvelles lignes après substitution "normale". Tout d'abord, il efface le char de la 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 la nouvelle ligne char) après avoir été découpé, avec une chaîne de votre choix, pour chaque ligne d'entrée; mais, sed produira différentes lignes. Exemple, supposons que vous vouliez remplacer la "fin de ligne" avec "===" (plus général que d'un remplacement par un espace simple):

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

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

pour remplacer les caractères de la nouvelle ligne par la chaîne, vous pouvez, de manière inefficace, utiliser tr , comme indiqué ci-dessus, pour remplacer les caractères de la nouvelle ligne par un" caractère spécial "et ensuite utiliser sed pour remplacer ce caractère spécial par la chaîne que vous voulez.

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
répondu Robert Vila 2014-04-16 05:47:53

@OP, si vous voulez remplacer newlines dans un fichier, vous pouvez juste utiliser dos2unix (ou unix2dox)

dos2unix yourfile yourfile
2
répondu ghostdog74 2009-08-10 00:49:14

pour supprimer les lignes vides:

sed -n "s/^$//;t;p;"
2
répondu kralyk 2011-06-06 14:42:25

vous pouvez utiliser cette méthode aussi

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.

"151990920 Flux":

Lorsque la première ligne est obtenue à partir de l'entrée, l'échange est fait, donc 1 va à hold space et \n vient à pattern space, puis en ajoutant l'espace hold à pattern space, puis la substitution est effectuée et supprimé l'espace pattern.

Pendant l'échange de deuxième ligne est fait, 2 va pour contenir d'espace et 1 le modèle de l'espace, puis G ajoute le espace dans le modèle de l'espace, puis h copier le modèle et la substitution est faite et supprimés. Cette opération est poursuivie jusqu'à ce que l'eof soit atteint, puis imprimer le résultat exact.

2
répondu Kalanidhi 2014-07-18 19:26:05

un autre GNU sed méthode, presque la même que Zsolt Botykai 's answer , mais cela utilise sed 'S moins fréquemment utilisé y ( translitterate ) commande, qui sauve one byte of code (the trailing g ):

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

on pourrait espérer que y courrait plus vite que s , (peut-être à des vitesses de tr , 20x plus rapides), mais dans GNU sed v4.2.2 y est d'environ 4% plus lent que s .


plus portable BSD sed version:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
2
répondu agc 2018-09-13 13:39:31
sed '1h;1!H;$!d
     x;s/\n/ /g' YourFile

cela ne fonctionne pas pour les gros fichiers (limite de la mémoire tampon), mais c'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
répondu NeronLeVelu 2016-11-03 19:33:53

j'ai posté cette réponse parce que j'ai essayé avec la plupart des sed l'exemple de recommandation fourni ci-dessus qui ne fonctionne pas pour moi dans ma boîte Unix et me donnant 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 tout L'environnement 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 supprimera tous les des espaces.

1
répondu Abhijit Pritam Dutta 2018-03-22 22:20:37