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?
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:
- créer une étiquette via
:a
. - ajoute la ligne courante et la ligne suivante à l'espace de motif via
N
. - 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). - 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 .
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
réponse rapide:
sed ':a;N;$!ba;s/\n/ /g' file
- :un créer une étiquette " a "
- N ajouter la ligne suivante à l'espace de dessin
- $! si ce n'est la dernière ligne , ba "1519170920 branche" (aller à) l'étiquette "a"
- 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.
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.
gnu sed a une option -z
pour les enregistrements (lignes) séparés. Vous pouvez simplement appeler:
sed -z 's/\n/ /g'
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.
qui a besoin de sed
? Voici le bash
chemin:
cat test.txt | while read line; do echo -n "$line "; done
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
trois choses.
-
tr
(oucat
, 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. -
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 confondentsed
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. Essayezed
; 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 justesed
. -
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.
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.
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.
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.
-
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é. -
"utiliser
sed
pour correspondre auNULL
-
Utiliser
tr
pour échanger des nouvelles lignes supplémentaires si vous en avez besoin
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'
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'`
à 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.
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.
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.
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
Utilisant Awk:
awk "BEGIN { o=\"\" } { o=o \" \" $0 } END { print o; }"
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.
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>
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~$
@OP, si vous voulez remplacer newlines dans un fichier, vous pouvez juste utiliser dos2unix (ou unix2dox)
dos2unix yourfile yourfile
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.
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/ /'
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
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.