40 votes

Insérer un saut de ligne dans sed (Mac OS X)

Comment insérer une nouvelle ligne dans la partie de remplacement de sed ?

Ce code ne fonctionne pas :

sed "s/\(1234\)/\n\1/g" input.txt > output.txt

où se trouve input.txt :

test1234foo123bar1234

et output.txt devrait être :

test
1234foo123bar
1234

mais à la place, j'obtiens ceci :

testn1234foo123barn1234

NOTE :

Cette question concerne spécifiquement la version Mac OS X de "sed", et la communauté a remarqué qu'elle se comporte différemment des versions Linux, par exemple.

61voto

przemoc Points 1317

Votre version de sed ne supporte apparemment pas \n dans RHS (côté droit de la substitution). Vous devez lire LA FAQ SED maintenu par Eric Pement pour choisir une des solutions possibles. Je suggère d'essayer d'abord d'insérer un caractère de nouvelle ligne littéral.

Vous trouverez ci-dessous une citation de ce document.


4.1. Comment insérer un saut de ligne dans le RHS d'une substitution ?

Plusieurs versions de sed permettent \n à taper directement dans le RHS, qui est ensuite converti en une nouvelle ligne sur la sortie : ssed, gsed302a+, gsed103 (avec l'option -x ), sed15+, sedmod, et UnixDOS sed. La solution la plus simple est d'utiliser l'une de ces versions.

Pour d'autres versions de sed, essayez l'une des méthodes suivantes :

(a) Si vous tapez la commande sed script à partir d'un interpréteur de commandes Bourne, utilisez un backslash \ si le script utilise des 'guillemets simples' ou deux backslashes \\ si le script nécessite des "guillemets doubles". Dans l'exemple ci-dessous, notez que les guillemets > sur la 2ème ligne est généré par le shell pour demander à l'utilisateur de saisir plus de données. L'utilisateur tape slash, single-quote, puis ENTER pour terminer la commande :

 [sh-prompt]$ echo twolines | sed 's/two/& new\
 >/'
 two new
 lines
 [bash-prompt]$

(b) Utiliser un fichier script avec un backslash \ dans le script, immédiatement suivi d'une nouvelle ligne. Cela permettra d'intégrer une nouvelle ligne dans la partie "replace". Exemple :

 sed -f newline.sed files

 # newline.sed
 s/twolines/two new\
 lines/g

Certaines versions de sed peuvent ne pas avoir besoin de la barre oblique inversée de fin de ligne. Si c'est le cas, supprimez-la.

(c) Insérez un caractère non utilisé et faites passer la sortie par tr :

 echo twolines | sed 's/two/& new=/' | tr "=" "\n"   # produces
 two new
 lines

(d) Utilisez le G commandement :

G ajoute une nouvelle ligne, plus le contenu de l'espace de maintien à la fin de l'espace de motif. Si l'espace de maintien est vide, une nouvelle ligne est quand même ajoutée. Le saut de ligne est stocké dans l'espace de motif en tant que \n où il peut être abordé en regroupant \(...\) et s'est déplacé dans l'ERS. Ainsi, pour modifier l'exemple "twolines" utilisé précédemment, le script suivant fonctionnera :

 sed '/twolines/{G;s/\(two\)\(lines\)\(\n\)/\1\3\2/;}'

(e) Insertion de lignes entières, pas de rupture de lignes :

Si l'on ne change pas de ligne mais que l'on insère seulement des lignes complètes avant ou après un motif, la procédure est beaucoup plus facile. Utilisez le bouton i (insérer) ou a (append), en effectuant les modifications par un script externe. Pour insérer This line is new AVANT chaque ligne correspondant à une regex :

 /RE/i This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{x;s/$/This line is new/;G;}     # other seds

Les deux exemples ci-dessus sont prévus comme des commandes "d'une ligne" entrées depuis la console. Si vous utilisez un sed script, i\ immédiatement suivie d'une nouvelle ligne littérale fonctionnera sur toutes les versions de sed. En outre, la commande s/$/This line is new/ ne fonctionnera que si l'espace d'attente est déjà vide (ce qui est le cas par défaut).

Pour ajouter This line is new APRÈS chaque ligne correspondant à une regex :

 /RE/a This line is new               # HHsed, sedmod, gsed 3.02a
 /RE/{G;s/$/This line is new/;}       # other seds

Pour ajouter 2 lignes vides après chaque ligne correspondant à une regex :

 /RE/{G;G;}                    # assumes the hold space is empty

Pour remplacer chaque ligne correspondant à une expression rationnelle par 5 lignes vides :

 /RE/{s/.*//;G;G;G;G;}         # assumes the hold space is empty

(f) Utilisez le y/// si possible :

Sur certaines versions Unix de sed (pas GNU sed !), bien que l'option s/// n'acceptera pas \n dans l'ERS, le y/// le fait. Si votre Unix sed le supporte, une nouvelle ligne après aaa peut être inséré de cette façon (qui n'est pas portable à GNU sed ou à d'autres seds) :

 s/aaa/&~/; y/~/\n/;    # assuming no other '~' is on the line!

20voto

mklement0 Points 12597

Voici un solution monoligne qui fonctionne avec tout Compatible avec POSIX sed (y compris la version FreeBSD sur macOS), en supposant que votre shell est bash ou ksh ou zsh :

sed 's/\(1234\)/\'$'\n''\1/g' <<<'test1234foo123bar1234'

Notez que vous pourrait utiliser un simple Une chaîne de caractères citée en ANSI C en tant que tout le site sed script, sed $'...' <<< mais cela nécessiterait \ -Escaping all \ (les doublant), ce qui est assez lourd et nuit à la lisibilité, comme en témoigne La réponse de @tovk ).

  • $'\n' représente une nouvelle ligne et est une instance de Cotation ANSI C qui vous permet de créer des chaînes de caractères avec des séquences d'échappement de caractères de contrôle.
  • Ce qui précède épissures la chaîne de caractères citée en ANSI C en le site sed script comme suit :
    • Le script est simplement divisée en deux chaînes de caractères à guillemets simples, avec la chaîne de caractères C ANSI coincée entre les deux moitiés. :
    • 's/\(1234\)/\' est la première moitié - notez qu'elle se termine par \ afin d'échapper à la nouvelle ligne qui sera insérée dans le caractère suivant. (cet échappement est nécessaire pour marquer la nouvelle ligne comme faisant partie de la chaîne de remplacement plutôt que d'être interprétée comme la fin de la commande).
    • $'\n' est la représentation du caractère de nouvelle ligne dans le langage C de l'ANSI, que la coquille s'étend à une réel nouvelle ligne avant de transmettre le script à sed .
    • '\1/g' est la seconde moitié.

Notez que cette solution fonctionne de manière analogue pour les autres caractères de contrôle tels que $'\t' pour représenter un caractère de tabulation.


Informations générales :

  • Le système POSIX sed spécification : http://man.cx/sed
    • BSD sed (également utilisé sur macOS) reste proche de cette spécification, alors que GNU sed offre de nombreuses extensions.
  • Un résumé des différences entre GNU sed et BSD sed peut être trouvé à https://stackoverflow.com/a/24276470/45375

8voto

bmk Points 6832

La version solaris de sed Je pourrais convaincre de travailler de cette façon (dans bash ) :

echo test1234foo123bar1234 | sed 's/\(1234\)/\
\1/g'

(vous devez placer le saut de ligne directement après la barre oblique inversée).

Sur csh J'ai dû mettre une barre oblique inversée de plus :

echo test1234foo123bar1234 | sed 's/\(1234\)/\\
\1/g'

La version Gnu de sed a simplement fonctionné en utilisant \n :

echo test1234foo123bar1234 | sed 's/\(1234\)/\n\1/g'

8voto

Phil Points 1780

Perl fournit une syntaxe regex "étendue" plus riche qui est utile ici :

perl -p -e 's/(?=1234)/\n/g'

signifie "substituer une nouvelle ligne à la correspondance de largeur nulle suivant le motif 1234". Cela évite d'avoir à capturer et à répéter une partie de l'expression avec des rétro-références.

2voto

rid Points 24625

Malheureusement, pour moi, sed semble ignorer \n dans la chaîne de remplacement.

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\n\1/g"
testn1234foo123barn1234

Si cela vous arrive à vous aussi, une alternative est d'utiliser :

$ echo test1234foo123bar1234 | sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g"

Cela devrait fonctionner partout et produire :

test
1234foo123bar
1234

Pour votre exemple avec un input.txt comme entrée et output.txt comme sortie, utiliser :

$ sed "s/\(1234\)/\\`echo -e '\n\r'`\1/g" input.txt > output.txt

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X