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

1371

Comment puis-je remplacer une nouvelle ligne (" \n") par un espace (" ") à l'aide de la sedcommande?

J'ai essayé sans succès:

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

Comment je le répare?

hhh
la source
27
trn'est le bon outil pour le travail que si remplacer un seul caractère par un seul caractère, tandis que l'exemple ci-dessus montre remplacer la nouvelle ligne par un espace. Donc dans l'exemple ci-dessus, tr pourrait fonctionner .. Mais serait limitant plus tard.
Angry 84
9
trdans le bon outil pour le travail parce que le questionneur voulait remplacer chaque nouvelle ligne par un espace, comme le montre son exemple. Le remplacement des sauts de ligne est uniquement mystérieux sedmais facile à réaliser tr. C'est une question courante. Effectuer des remplacements de regex ne se fait pas par trmais par sed, ce qui serait le bon outil ... pour une question différente.
Mike S
3
"tr" peut aussi simplement supprimer la nouvelle ligne `tr -d '\ n' 'mais vous pouvez également supprimer les retours pour être plus universel` tr -d' \ 012 \ 015 ''.
anthony
2
AVERTISSEMENT: "tr" agit différemment en ce qui concerne une plage de caractères entre Linux et les anciennes machines Solaris (EG sol5.8). EG: `tr -d 'az' 'et` tr -d' [az] ''. Pour cela, je vous recommande d'utiliser "sed" qui n'a pas cette différence.
anthony
2
@MikeS Merci pour la réponse. Suivez tr '\012' ' 'avec un echo. Sinon, le dernier saut de ligne du fichier est également supprimé. tr '\012' ' ' < filename; echofait l'affaire.
Bernie Reiter

Réponses:

1514

Utilisez cette solution avec GNU sed:

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

Cela 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 de motif via N.
  3. Si nous sommes avant la dernière ligne, branchez-vous sur l'étiquette créée $!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 sur l'espace de motif (qui est le fichier entier).

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

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

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

Zsolt Botykai
la source
45
@Arjan et Masi: OS X utilise BSD sedplutôt que GNU sed, il peut donc y avoir des différences subtiles (et pas si subtiles) entre les deux. C'est une douleur constante si vous travaillez sur des machines OS X et * nix. J'installe habituellement GNU coreutilset findutilssur OS X, et j'ignore les versions BSD.
Télémaque
50
Ce :an'est pas un registre, c'est une étiquette de branche. C'est une cible pour la bcommande * qui fonctionne comme "goto". L'appeler un registre implique que vous pouvez créer des emplacements de stockage. Il n'y a que deux "registres"; l'un est appelé "l'espace d'attente" que votre script n'utilise pas et l'autre est appelé "l'espace modèle". La Ncommande ajoute une nouvelle ligne et la ligne suivante du fichier d'entrée à l'espace de motif. [* Vous pouvez avoir plusieurs étiquettes et bcommandes. Si une bcommande sans caractère char est ajoutée, elle se ramifie à la fin du script pour lire la ligne suivante et boucler à nouveau.]
pause jusqu'à nouvel ordre.
108
Vous pouvez exécuter cette multiplateforme (c'est-à-dire sur Mac OS X) en exécutant séparément les commandes plutôt qu'en les séparant par des points-virgules: sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
Benjie
74
Pourquoi personne ne commente ce qu'est un désordre stupide (pas la réponse elle-même, mais le programme pour lequel la réponse proposée est la meilleure solution à un problème très simple). Sed ressemble à une voiture qui fonctionne généralement bien, mais si vous voulez conduire dans une rue voisine spécifique, la seule façon est de soulever la voiture avec un hélicoptère.
Ark-kun
12
Allez les amis - 261 votes positifs pour une solution folle et incompréhensible qui ne fonctionne pas ???? sed est un excellent outil pour des substitutions simples sur une seule ligne, pour tout le reste, utilisez simplement awk. Bon deuil ....
Ed Morton
1711

sedest destiné à être utilisé sur une entrée en ligne. Bien qu'il puisse faire ce dont vous avez besoin.


Une meilleure option ici consiste à utiliser la trcommande comme suit:

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 longues options)

tr --delete '\n' < input.txt > output.txt
dmckee --- chaton ex-modérateur
la source
88
Sed est basé sur des lignes, il lui est donc difficile de saisir de nouvelles lignes.
Alexander Gladysh
191
sed fonctionne sur un "flux" d'entrées, mais il le comprend en segments délimités par des sauts de ligne. C'est un outil Unix, ce qui signifie qu'il fait très bien une chose. La seule chose est de "travailler sur un fichier en ligne". Le faire faire autre chose sera difficile et risque d'être bogué. La morale de l'histoire est: choisissez le bon outil. Un grand nombre de vos questions semblent prendre la forme "Comment puis-je faire en sorte que cet outil fasse quelque chose qu'il n'a jamais été censé faire?" Ces questions sont intéressantes, mais si elles se posent au cours de la résolution d'un problème réel, vous vous trompez probablement.
dmckee --- chaton ex-modérateur
7
@JBBrown trest un joyau souvent négligé pour la construction de pipelines.
dmckee --- chaton ex-modérateur
70
tr est génial, mais vous ne pouvez remplacer les sauts de ligne que par des caractères uniques. Vous devez utiliser un outil différent si vous souhaitez remplacer les sauts de ligne par une chaîne
Eddy
21
@Eddy - J'ai utilisé tr pour remplacer les nouvelles lignes par un caractère qui n'apparaissait pas dans le texte (j'ai utilisé backtick), puis sed pour remplacer le backtick par la chaîne que je voulais utiliser
rjohnston
494

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 de motif
  3. $! si ce n'est pas la dernière ligne , ba branche (allez à) étiquette 'a'
  4. s remplacer , / \ n / regex pour la nouvelle ligne , / / par un espace , / g correspondance globale (autant de fois que possible)

sed effectuera une boucle à travers les étapes 1 à 3 jusqu'à ce qu'il atteigne la dernière ligne, pour que toutes les lignes tiennent dans l'espace du modèle où sed remplacera tous les \ n caractères


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 semblable à sed

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

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

tr '\n' ' ' < file

avec pâte , vitesse tr- like, peut remplacer par un seul caractère

paste -s -d ' ' file

avec vitesse awk , tr- like

awk 1 ORS=' ' file

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


Réponse longue de la FAQ sed 5.10

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

Le \ n ne correspondra jamais à la nouvelle ligne à la fin de la ligne car le
nouvelle ligne est toujours supprimée avant que la ligne ne soit placée dans l'
espace de motif. Pour obtenir 2 lignes ou plus dans l'espace de 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
nouvelle ligne de fin, place ce qui reste dans l'espace de modèle où
le script sed peut l'adresser ou le modifier, et lorsque l'espace de modèle
est imprimé, ajoute une nouvelle ligne à stdout (ou vers un fichier). Si l'
espace de motif est entièrement ou partiellement supprimé avec 'd' ou 'D', la
nouvelle ligne n'est pas ajoutée 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 que
la ligne ne soit placée dans l'espace de motif. 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          

Étant donné que les versions de sed autres que GNU sed ont des limites à la taille du
tampon de modèle, l'utilitaire «tr» d'Unix est préférable ici.
Si la dernière ligne du fichier contient une nouvelle ligne, GNU sed ajoutera
cette nouvelle ligne à la sortie mais supprimera toutes les autres, tandis que tr
supprimera toutes les nouvelles lignes.

Pour faire correspondre un bloc de deux lignes ou plus, il y a 3 choix de base:
(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 actuelle
à 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) mettront un \ n dans l'espace modèle, où il
pourra être adressé comme souhaité ('s / ABC \ nXYZ / alphabet / g'). Un exemple
d'utilisation de «N» pour supprimer un bloc de lignes apparaît dans la section 4.13
(«Comment supprimer un bloc de lignes consécutives spécifiques ?»). Cet
exemple peut être modifié en remplaçant la commande delete par
autre chose , comme 'p' (impression), 'i' (insertion), 'c' (changement), 'a' (ajout),
ou 's' (remplacement) .

Choice (3) ne sera pas mettre \ n dans l'espace de travail , mais il ne
correspond un bloc de lignes consécutives, donc il se peut que vous n'avez pas
même besoin \ n pour trouver ce que vous cherchez. Depuis GNU sed
version 3.02.80 prend désormais en charge cette syntaxe:

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

en plus des
adresses traditionnelles "/ d'ici /, / là-bas / {...}" , il peut être possible d'éviter complètement l'utilisation de \ n.

hdorio
la source
6
trétait une excellente idée, et votre couverture globale en fait une réponse de qualité supérieure.
New Alexandria
1
+1 pour l'utilisation ( utilitaire standard ) paste... et tous les autres!
Totor
1
@elgalu essayez ceci unix.stackexchange.com/questions/4527/…
hdorio
4
La meilleure partie de cette réponse est que la "réponse longue" explique exactement comment et pourquoi la commande fonctionne.
pdwalker
3
C'est peut-être la plus utile des milliers de réponses que j'ai lues sur stackexchange. J'ai besoin de faire correspondre plusieurs caractères sur plusieurs lignes. Aucun exemple sed précédent ne couvrait plusieurs lignes et tr ne peut pas gérer la correspondance de plusieurs caractères. Perl a l'air bien, mais ne fonctionne pas comme prévu. Je voterais cette réponse plusieurs fois si je le pouvais.
mightypile
225

Une alternative awk plus courte:

awk 1 ORS=' '

Explication

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

condition { code-block }

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

Lors de la awklecture de l'entrée, il la divise en enregistrements en fonction de la valeur de RS(Séparateur d'enregistrements), qui par défaut est une nouvelle ligne, awkanalysera donc par défaut l'entrée en ligne. Le fractionnement implique également la suppression RSde l'enregistrement d'entrée.

Maintenant, lors de l'impression d'un enregistrement, ORS(Séparateur d'enregistrements de sortie) lui est ajouté, la valeur par défaut est à nouveau une nouvelle ligne. Ainsi, en changeant ORSen espace, toutes les nouvelles lignes sont changées en espaces.

Thor
la source
5
J'aime beaucoup cette solution simple, qui est beaucoup plus lisible que les autres
Fedir RYKHTIK
8
Si cela a plus de sens, cela pourrait effectivement s'écrire: awk 'BEGIN { ORS=" " } { print $0 } END { print "\n"} ' file.txt(en ajoutant un retour à la ligne de fin juste pour illustrer le début / la fin); le "1" est évalué pour true(traiter la ligne) et print(imprimer la ligne). Un conditionnel pourrait également être ajouté à cette expression, par exemple en ne travaillant que sur des lignes correspondant à un motif: awk 'BEGIN { ORS=" " } /pattern/ { print $0 } END { print "\n"} '
michael
2
Vous pouvez le faire plus simplement: codeawk 'ORS = ""' file.txtcode
Udi
Lorsque vous utilisez awk comme ceci, malheureusement, le dernier saut de ligne du fichier est également supprimé. Voir la réponse de Patrick Dark ci-dessus sur l'utilisation de 'tr' dans un sous-shell comme `cat file | echo $ (tr "\ 012" "") `qui fait l'affaire. Nifty.
Bernie Reiter
143

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

sed -z 's/\n/ /g'
JJoao
la source
4
Même si l'entrée contient des valeurs nulles, elles seront conservées (en tant que délimiteurs d'enregistrement).
Toby Speight
6
Cela ne chargera-t-il pas toute l'entrée s'il n'y a pas de valeurs nulles? Dans ce cas, le traitement d'un fichier de plusieurs gigaoctets peut se bloquer.
Ruslan
3
@Ruslan, oui, il charge toute l'entrée. Cette solution n'est pas une bonne idée pour les fichiers de plusieurs gigaoctets.
JJoao
7
C'est vraiment la meilleure réponse. Les autres expressions sont trop déformées pour être mémorisées. @JJoao Vous pouvez l'utiliser avec -u, --unbuffered. Le manmage déclare: "charger des quantités minimales de données à partir des fichiers d'entrée et vider les tampons de sortie plus souvent".
not2qubit
donc. beaucoup. cette.
sjas
85

La version Perl fonctionne comme vous vous y attendiez.

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

Comme indiqué dans les commentaires, il convient de noter que cette modification est en place. -i.bakvous donnera une sauvegarde du fichier d'origine avant le remplacement au cas où votre expression régulière ne serait pas aussi intelligente que vous le pensiez.

ire_and_curses
la source
23
Veuillez au moins mentionner que -isans suffixe ne fait aucune sauvegarde . -i.bakvous protège d'une erreur simple et laide (par exemple, en oubliant de taper -pet en remettant à zéro le fichier).
Télémaque
6
@Telemachus: C'est un bon point, mais il peut être argumenté de toute façon. 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 réellement 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 ma ligne de commande rallonge de quatre caractères. Pour le meilleur ou pour le pire (probablement pire), je suis un minimaliste compulsif; Je préfère juste la brièveté. Je sais que tu n'es pas d'accord. Je ferai de mon mieux pour ne pas oublier d'avertir des sauvegardes à l'avenir.
ire_and_curses
6
@Ire_and_curses: En fait, vous venez de faire un putain de bon argument pour m'ignorer. Autrement dit, vous avez des raisons pour vos choix, et si je suis d'accord ou non avec ces choix, je respecte certainement cela. Je ne sais pas trop pourquoi, mais j'ai été en larmes à propos de cette chose particulière récemment (le -idrapeau en Perl sans suffixe). Je suis sûr que je trouverai quelque chose d'autre à obséder assez tôt. :)
Télémaque
Il est vraiment regrettable que cela ne fonctionne pas avec stdin en spécifiant le -nom de fichier. Y-a-t-il un moyen de faire ça? C'est ma façon de ne pas vous soucier de modifier un fichier en utilisant un pipeline qui commence par cat.
Steven Lu
@StevenLu Perl lira par défaut à partir de STDIN si aucun nom de fichier n'est fourni. Vous pouvez donc faire par exempleperl -i -p -e 's/\n//' < infile > outfile
ire_and_curses
44

Qui a besoin sed? Voici le bashchemin:

cat test.txt |  while read line; do echo -n "$line "; done
pic commun
la source
2
Upvote, j'ai normalement utilisé la première réponse, mais lorsque vous passez / dev / urandom à travers elle, sed n'imprimera pas avant EOF et ^ C n'est pas EOF. Cette solution s'imprime chaque fois qu'elle voit une nouvelle ligne. Exactement ce dont j'avais besoin! Merci!
Vasiliy Sharapov, le
1
alors pourquoi pas: echo -n `cat days.txt` De cet article
Tony
9
@Tony car les backticks sont obsolètes et le chat est redondant ;-) Utilisation: echo $ (<days.txt)
seumasmac
10
Sans même en utilisant cat: while read line; do echo -n "$line "; done < test.txt. Peut être utile si un sous-shell pose problème.
Carlo Cannas
5
echo $(<file)serre tous les espaces dans un seul espace, pas seulement les nouvelles lignes: cela va au-delà de ce que l'OP demande.
glenn jackman
27

Afin de remplacer tous les sauts de ligne par des espaces 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
En pause jusqu'à nouvel ordre.
la source
END{ print ""}est une alternative plus courte pour une nouvelle ligne de fin.
Isaac
22
tr '\n' ' ' 

est la commande.

Simple et facile à utiliser.

Dheeraj R
la source
14
ou simplement tr -d '\n'si vous ne voulez pas ajouter d'espace
spuder
21

Trois choses.

  1. tr(ou cat, etc.) n'est absolument pas nécessaire. (GNU) sedet (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. edest un éditeur en ligne. sedn'est pas. Voir la conférence sed pour plus d'informations sur la différence. La plupart des gens confondent sedêtre basé sur les lignes car il est, par défaut, pas très gourmand dans sa correspondance de modèle pour les correspondances SIMPLES - par exemple, lors de la recherche de modèle et du remplacement par un ou deux caractères, il ne remplace par défaut que lors de la première correspondance 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 de courir ed; vous remarquerez la différence. edest assez utile si vous voulez parcourir des lignes spécifiques (comme dans une boucle for), mais la plupart du temps, vous le voudrez sed.

  3. Cela étant dit,

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

    fonctionne très bien dans GNU sedversion 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 {}« s peuvent être laissés, car ils sont inclus uniquement pour des raisons de santé mentale.

brent saner
la source
3
En tant que personne qui en sait seulement assez sedpour faire des trucs de base, je dois dire que c'est plus que ce que vous pouvez faire sedmais plutôt combien il est facile de comprendre ce qui se passe. J'ai du mal à travailler avec, seddonc je préférerais une commande plus simple quand je peux l'utiliser.
Nate
En utilisant t qcomme saut conditionnel, cela fonctionne avec un modèle comme s/\n / /(pour joindre toutes les lignes qui commencent par un espace) sans lire tout le fichier en mémoire. Pratique lors de la transformation de fichiers de plusieurs mégaoctets.
SMShell
L'article que vous avez lié ne reflète pas ce que vous dites
hek2mgl
Ceci est presque 800 fois plus lent que la réponse acceptée pour les entrées de grande taille. Cela est dû au remplacement de chaque ligne sur une entrée de plus en plus importante.
Thor
13

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

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

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

(écho foo; écho 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 ...

> (écho 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.

Juan
la source
La série d'arguments -e a fonctionné pour moi sur les fenêtres utilisant MKS! Merci!
JamesG
12

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 ) sedet tr:

$ echo 'foo
bar
baz


foo2
bar2
baz2' \
| tr '\n' '\000' \
| sed 's:\x00\x00.*:\n:g' \
| tr '\000' '\n'

Production:

foo
bar
baz

(a une nouvelle ligne de fin)

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

  1. Utilisez trpour échanger la nouvelle ligne avec un autre caractère.

    NULL( \000ou \x00) est agréable car il n'a pas besoin de support UTF-8 et il est peu probable qu'il soit utilisé.

  2. Utilisez sedpour faire correspondre leNULL

  3. Utilisez trpour échanger des nouvelles lignes supplémentaires si vous en avez besoin

CoolAJ86
la source
1
Une note subtile sur la nomenclature: le caractère \000est communément appelé NUL(un L), et NULLest généralement utilisé lorsque l'on parle d'un pointeur zéro (en C / C ++).
sqweek
11

Vous pouvez utiliser des xargs :

seq 10 | xargs

ou

seq 10 | xargs echo -n
Vytenis Bivainis
la source
Travaille pour moi: xargs < file.txt
Udi
9

Je ne suis pas un expert, mais je suppose que sedvous devez d'abord ajouter la ligne suivante dans l'espace de motif, 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 multiligne suivante (N) 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 de motif 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 de modèle, et non au (x) caractère (s) suivant un ou des sauts de ligne incorporés. De même, "$" ne correspond qu'à la nouvelle ligne finale dans l'espace de motif, et non à aucune nouvelle ligne incorporée. Une fois la commande Next exécutée, le contrôle est ensuite passé aux commandes suivantes du script.

De man sed:

[2addr] N

Ajoutez la ligne d'entrée suivante à l'espace de motif, à l'aide d'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".

Arjan
la source
7

J'ai utilisé une approche hybride pour contourner la nouvelle ligne en utilisant tr pour remplacer les nouvelles lignes par des tabulations, puis en remplaçant les tabulations par ce que je veux. Dans ce cas, "
" car j'essaie de générer des ruptures HTML.

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

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

tr '\n' ' ' < input

ne fonctionnait pas pour moi, ce serait une erreur ou remplacer réellement le \ nw / '' pour une raison quelconque.

En utilisant une autre fonctionnalité de tr, l'option "supprimer" -d a bien fonctionné:

tr -d '\n' < input

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

John Lawler
la source
3
Sous Windows, vous devrez probablement utiliser tr "\n" " " < input. Le shell Windows (cmd.exe) ne traite pas l'apostrophe comme un caractère de citation.
Keith Thompson
Non, dans le sous-système Windows 10 Ubuntu, vous devez utilisertr "\n\r" " " < input.txt > output.txt
user1491819
Cela fonctionne sur Windows 10 à l' aide GnuWin32: cat SourceFile.txt | tr --delete '\r\n' > OutputFile.txt. Ou, au lieu de Gnuwin32, utilisez Gow (Gnu sur Windows), github.com/bmatzelle/gow/wiki
Alchemistmatt
5

Solution pare-balles. Sécuritaire pour les données binaires et compatible POSIX, mais lent.

POSIX sed nécessite une entrée conformément au fichier texte POSIX et aux définitions de ligne POSIX , donc les octets NULS 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 le traitement de données d'entrée arbitraires.

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

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

Les deux read, [et printfsont intégrés dans au moins bash, mais ce n'est probablement pas garanti par POSIX, donc sur certaines plateformes, il se pourrait que chaque octet d'entrée démarre un ou plusieurs nouveaux processus, ce qui ralentira les choses. Même en bash, cette solution n'atteint qu'environ 50 kB / s, elle n'est donc pas adaptée aux gros fichiers.

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

Håkon A. Hjortland
la source
5

Dans certaines situations, vous pouvez peut-être changer RSpour 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

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 bien des fois, vous avez plus de choses à prendre en compte que de trouver une solution complexe à un problème simple.

Concernant la chose que gawk est lent ... et lit le fichier en mémoire, je ne sais pas, mais pour moi gawk semble fonctionner avec une ligne à la fois et est très très rapide (pas aussi rapide que certains des autres) , mais le temps d’écrire et de 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.

mor
la source
5

Si vous avez la malchance de devoir gérer les fins de ligne Windows, vous devez supprimer le \ret le\n

tr '[\r\n]' ' ' < $input > $output
StevenWernerCS
la source
Cela remplace [par un espace, et \rpar un espace, et \npar un espace, et ]par un espace. tr -d '\r\n' <filesupprimerait tout \rou plusieurs \ncaractères, mais ce n'est pas non plus ce qui est demandé. tr -d '\r' <filesupprimera tous les \rcaractères (qu'ils soient adjacents ou non \n) ce qui est probablement plus proche d'être utile ainsi que très probablement correct pour les besoins de l'OP (en supposant toujours que vous trcompreniez cette notation barre oblique inverse).
tripleee
4

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

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

cnst
la source
xargs gère également bien la dernière ligne:
AAAfarmclub
4

Recherche et remplace à l'aide de l'autorisation \ n

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

Marqueur

Devient

# Commentaire du marqueur

Marqueur

Proximo
la source
4

Pourquoi n'ai-je pas trouvé de solution simple awk?

awk '{printf $0}' file

printf imprimera chaque ligne sans retour à la ligne, si vous souhaitez séparer les lignes originales par un espace ou autre:

awk '{printf $0 " "}' file
Itachi
la source
echo "1\n2\n3" | awk '{printf $0}', cela fonctionne pour moi. @ edi9999
Itachi
Vous avez raison désolé, j'ai oublié le fin printf
edi9999
c'était la seule approche qui fonctionnait pour moi dans git bash pour windows
Platon
3

Sous 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
bashfu
la source
3

Pour supprimer des lignes vides:

sed -n "s/^$//;t;p;"
Kralyk
la source
C'est pour GNU Sed. Dans Sed normal, cela donne sed: 1: "s/^$//;t;p;": undefined label ';p;'.
Léo Léopold Hertz
3

Utilisation d'Awk:

awk "BEGIN { o=\"\" }  { o=o \" \" \$0 }  END { print o; }"
Kralyk
la source
2
Vous n'avez pas besoin d'échapper aux guillemets et au signe dollar si vous changez les guillemets extérieurs en guillemets simples. La lettre "o" est généralement considérée comme un mauvais choix comme nom de variable car elle peut être confondue avec le chiffre "0". Vous n'avez pas non plus besoin d'initialiser votre variable, il s'agit par défaut d'une chaîne nulle. Toutefois, si vous ne voulez pas un espace de premier plan étrangers: awk '{s = s sp $0; sp = " "} END {print s}'. Cependant, voir ma réponse pour un moyen d'utiliser awk sans lire le fichier entier en mémoire.
pause jusqu'à nouvel ordre.
Veuillez plutôt vérifier la réponse de Thor . Il est beaucoup plus efficace, lisible et juste mieux par tous les moyens à cette approche par rapport (même si cela ne fonctionne)!
mschilli
Mec, je comprends. Pas besoin de me le frotter au visage :-) La réponse de Thor est de toute façon bien au dessus sur la page (ce qui est vrai), alors qu'importe!
kralyk
3

Une solution que j'aime particulièrement est d'ajouter tout le fichier dans l'espace d'attente et de remplacer tous les sauts de ligne à 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.

brandizzi
la source
1
le remplacement par une chaîne vide dans votre réponse masque le fait que toujours utiliser H pour ajouter à l'espace d'attente signifie que l'espace d'attente commencera par une nouvelle ligne. Pour éviter cela, vous devez utiliser1h;2,$H;${x;s/\n/x/g;p}
Jeff
3

Remplacez les sauts de ligne par n'importe quelle chaîne et remplacez également le dernier saut de ligne

Les trsolutions pures ne peuvent être remplacées que par un seul caractère, et les sedsolutions pures ne remplacent pas la dernière nouvelle ligne de l'entrée. La solution suivante résout ces problèmes et semble sûre pour les données binaires (même avec un environnement local 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>
Håkon A. Hjortland
la source
C'est mauvais car cela produira une sortie indésirable sur toute entrée contenant@
Steven Lu
@StevenLu: Non, @l'entrée est OK. Il s'échappe %aet revient. La solution n'est peut-être pas complètement compatible POSIX, cependant (les octets NULL ne sont pas autorisés, donc pas bon pour les données binaires, et toutes les lignes doivent se terminer par un retour à la ligne afin que la trsortie ne soit pas vraiment valide).
Håkon A. Hjortland
Ah. Je vois que tu l'as réparé. Un peu compliqué pour ce qui devrait être une opération simple, mais un bon travail.
Steven Lu
3

C'est sed qui introduit les nouvelles lignes après substitution "normale". Tout 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é coupé, avec une chaîne de votre choix, pour chaque ligne d'entrée; mais sed produira différentes lignes. Par exemple, supposons que vous vouliez remplacer la "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 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 spécial par la chaîne que vous souhaitez .

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~$
Robert Vila
la source
3

Vous pouvez également 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.

Flux:
Lorsque la première ligne provient de l'entrée, l'échange est effectué, donc 1 va pour conserver l'espace et \ n vient pour l'espace de motif, puis ajouter l'espace de maintien à l'espace de motif, puis la substitution est effectuée et supprimé l'espace de motif.
Au cours de la deuxième ligne, un échange est effectué, 2 va à l'espace de maintien et 1 vient à l'espace de motif, puis Gajoutez l'espace de maintien dans l'espace de motif, puish copiez le motif et la substitution est effectuée et supprimée. Cette opération se poursuit jusqu'à ce que eof soit atteint puis imprime le résultat exact.

Kalanidhi
la source
Cependant, soyez averti que cela se echo 'Y' | sed 'x;G;1!h;s/\n/X/g;$!d'traduit par XY.
Spooky
3

Une autre GNU sed méthode, presque le même que Zsolt Botykai 's réponse , mais cette utilisation sedde s moins fréquemment utilisés y( transliterate de commande), qui enregistre un octet de code (la fuite g):

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

On pourrait espérer yfonctionner plus vite que s, (peut-être à des trvitesses 20 fois plus rapides), mais dans GNU sed v4.2.2 y est environ 4% plus lent que s.


Version BSD plus portable sed:

sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'
agc
la source
2
Avec BSD sed yest environ 15% plus rapide. Voir cette réponse pour un exemple de travail.
Thor
De plus, avec BSD, les commandes sed doivent se terminer après une étiquette, ce sed -e ':a' -e 'N;$!ba' -e 'y/\n/ /'serait donc la voie à suivre.
ghoti