web-dev-qa-db-fra.com

Comment insérer une nouvelle ligne devant un motif?

Pas comment insérer une nouvelle ligne avant une ligne. Ceci demande comment insérer une nouvelle ligne avant un motif dans une ligne.

Par exemple,

sed 's/regexp/&\n/g'

insérera une nouvelle ligne derrière le motif regexp.

Comment puis-je faire la même chose mais devant le motif?

Voici un exemple de fichier d'entrée

somevariable (012)345-6789

Devraient devenir

somevariable
(012)345-6789
120
Dennis

Certaines des autres réponses n'ont pas fonctionné pour ma version de sed. Changer la position de & et \n a fonctionné.

sed 's/regexp/\n&/g' 

Edit: Cela ne semble pas fonctionner sous OS X, à moins d’installer gnu-sed.

39
Dennis

Cela fonctionne dans bash, testé sous Linux et OS X:

sed 's/regexp/\'$'\n/g'

En général, pour $ suivi d'un littéral de chaîne entre guillemets simples bash effectue une substitution de barre oblique inverse de style C, par ex. $'\t' est traduit en onglet littéral. De plus, sed souhaite que votre littéral newline soit échappé avec une barre oblique inverse, d’où le \ avant $. Enfin, le signe dollar lui-même ne doit pas être cité de manière à être interprété par Shell. Par conséquent, nous fermons la citation avant le $, puis nous l'ouvrons à nouveau.

Edit: Comme suggéré dans les commentaires de @ mklement0, cela fonctionne aussi bien:

sed $'s/regexp/\\\n/g'

Ce qui se passe ici est que: l'intégralité de la commande sed est maintenant une chaîne de style C. Cela signifie que la barre oblique inverse que sed nécessite d'être placée avant le nouveau littéral de ligne doit maintenant être échappée avec une autre barre oblique inverse. Bien que plus lisible, dans ce cas, vous ne pourrez pas effectuer de substitutions de chaînes dans Shell (sans les rendre à nouveau laides).

157
mojuba

Dans sed, vous ne pouvez pas ajouter facilement de nouvelles lignes dans le flux de sortie. Vous devez utiliser une ligne de continuation, ce qui est gênant, mais cela fonctionne:

$ sed 's/regexp/\
&/'

Exemple:

$ echo foo | sed 's/.*/\
&/'

foo

Voir ici pour plus de détails. Si vous voulez quelque chose de légèrement moins gênant, vous pouvez utiliser Perl -pe avec des groupes de correspondance au lieu de sed:

$ echo foo | Perl -pe 's/(.*)/\n$1/'

foo

$1 fait référence au premier groupe correspondant dans l'expression régulière, les groupes étant entre parenthèses.

32
Todd Gamblin

Sur mon mac, ce qui suit insère un seul 'n' au lieu de newline:

sed 's/regexp/\n&/g'

Ceci remplace par newline:

sed "s/regexp/\\`echo -e '\n\r'`/g"
28
Roar Skullestad
echo one,two,three | sed 's/,/\
/g'
14
vivek

Dans ce cas, je n'utilise pas sed. J'utilise tr.

cat Somefile |tr ',' '\012' 

Cela prend la virgule et la remplace par le retour chariot.

9
user1612632

Vous pouvez utiliser Perl one-liners un peu comme vous le faites avec sed, avec l'avantage du support complet expression régulière Perl (beaucoup plus puissant que ce que vous obtenez avec sed). Il y a également très peu de variation entre les plates-formes * nix - Perl est généralement Perl. Vous pouvez donc cesser de vous demander comment faire en sorte que la version de sed de votre système fasse ce que vous voulez.

Dans ce cas, vous pouvez faire

Perl -pe 's/(regex)/\n$1/'

-pe place Perl dans une boucle "exécuter et imprimer", un peu comme le mode de fonctionnement normal de sed.

' cite tout le reste pour que le shell n'interfère pas

() entourant la regex est un opérateur de regroupement. $1 sur le côté droit de la substitution affiche ce qui a été mis en correspondance dans ces parenthèses.

Enfin, \n est une nouvelle ligne.

Que vous utilisiez ou non des parenthèses en tant qu'opérateur de regroupement, vous devez échapper à toutes les parenthèses que vous essayez de faire correspondre. Donc, une expression rationnelle correspondant au motif que vous avez énuméré ci-dessus serait quelque chose comme:

\(\d\d\d\)\d\d\d-\d\d\d\d

\( ou \) correspond à un nom littéral, et \d correspond à un chiffre.

Mieux:

\(\d{3}\)\d{3}-\d{4}

J'imagine que vous pouvez comprendre ce que font les chiffres entre accolades.

En outre, vous pouvez utiliser des délimiteurs autres que/pour votre expression rationnelle. Donc, si vous avez besoin d'égaler/vous n'aurez pas besoin d'y échapper. L'un des éléments ci-dessous est équivalent à l'expression régulière au début de ma réponse. En théorie, vous pouvez substituer n'importe quel caractère aux/à la norme.

Perl -pe 's#(regex)#\n$1#'
Perl -pe 's{(regex)}{\n$1}'

Conseil en prime - si le paquet pcre est installé, il est livré avec pcregrep, qui utilise des expressions rationnelles compatibles Perl.

8
Dan Pritts

Hmm, les nouvelles lignes juste échappées semblent fonctionner dans les versions plus récentes de sed (j'ai GNU sed 4.2.1),

dev:~/pg/services/places> echo 'foobar' | sed -r 's/(bar)/\n\1/;'
foo
bar
4
gatoatigrado
echo pattern | sed -E -e $'s/^(pattern)/\\\n\\1/'

a bien fonctionné sur El Capitan avec le support ()

3
Quanlong

Pour insérer une nouvelle ligne dans le flux de sortie sous Linux, j'ai utilisé:

sed -i "s/def/abc\\\ndef/" file1

file1 était:

def

Avant le remplacement en place de sed, et:

abc
def

Après le remplacement sur place de sed. Veuillez noter l'utilisation de \\\n. Si les motifs contiennent un ", quittez-le avec \".

3
Karthik

Vous pouvez également le faire avec awk, en utilisant -v pour fournir le motif:

awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file

Ceci vérifie si une ligne contient un motif donné. Si c'est le cas, il ajoute une nouvelle ligne au début de celle-ci.

Voir un exemple de base:

$ cat file
hello
this is some pattern and we are going ahead
bye!
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
hello
this is some 
pattern and we are going ahead
bye!

Notez que cela affectera tous les motifs d'une ligne:

$ cat file
this pattern is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' d
this 
pattern is some 
pattern and we are going ahead
2
fedorqui

Après avoir lu toutes les réponses à cette question, il m'a fallu plusieurs tentatives pour obtenir la syntaxe correcte dans l'exemple de script suivant:

#!/bin/bash
# script: add_domain
# using fixed values instead of command line parameters $1, $2
# to show typical variable values in this example
ipaddr="127.0.0.1"
domain="example.com"
# no need to escape $ipaddr and $domain values if we use separate quotes.
Sudo sed -i '$a \\n'"$ipaddr www.$domain $domain" /etc/hosts

Le script ajoute une nouvelle ligne \n suivie d'une autre ligne de texte à la fin d'un fichier à l'aide d'une seule commande sed.

1
Xavier
sed -e 's/regexp/\0\n/g'

\ est la valeur null, votre expression est donc remplacée par la valeur null (rien), puis ...
\ n est la nouvelle ligne

Sur certaines versions d'Unix ne fonctionne pas, mais je pense que c'est la solution à votre problème.

echo "Hello" | sed -e 's/Hello/\0\ntmow/g'
Hello
tmow
1
tmow

dans sed, vous pouvez référencer des groupes dans votre modèle avec "\ 1", "\ 2", .... Ainsi, si le modèle que vous recherchez est "PATTERN", et que vous souhaitez insérer "BEFORE" devant celui-ci , vous pouvez utiliser, sans échapper

sed 's/(PATTERN)/BEFORE\1/g'

c'est à dire.

  sed 's/\(PATTERN\)/BEFORE\1/g'
1
Steve B.

Dans vi sur Red Hat, j'ai pu insérer des retours à la ligne en utilisant uniquement le caractère\r. Je pense que cela exécute en interne "ex" au lieu de "sed", mais c'est similaire, et vi peut être un autre moyen d'effectuer des éditions en bloc telles que des correctifs de code. Par exemple. J'entends un terme de recherche avec une instruction if qui insiste sur le fait que les retours de chariot après les accolades sont les suivants:

:.,$s/\(my_function(.*)\)/if(!skip_option){\r\t\1\r\t}/

Notez que je l'ai également fait insérer des onglets pour que les choses s'alignent mieux.

0
Robert Casey

Cela fonctionne dans MAC pour moi

sed -i.bak -e 's/regex/xregex/g' input.txt sed -i.bak -e 's/qregex/\'$'\nregex/g' input.txt

Dono si c'est parfait ...

0
sam