web-dev-qa-db-fra.com

Insérer une ligne après le premier match en utilisant sed

Pour une raison quelconque, je n'arrive pas à trouver une réponse simple à cette question et je suis un peu pressé en ce moment. Comment puis-je insérer une ligne de texte de choix après la première ligne correspondant à une chaîne spécifique à l'aide de la commande sed? J'ai ...

CLIENTSCRIPT="foo"
CLIENTFILE="bar"

Et je veux insérer une ligne après la ligne CLIENTSCRIPT= entraînant ...

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"
194
user2150250

Essayez de faire ceci en utilisant GNU sed:

sed '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

si vous voulez remplacer in-place, utilisez

sed -i '/CLIENTSCRIPT="foo"/a CLIENTSCRIPT2="hello"' file

Sortie

CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"

Doc

  • voir sed doc et chercher \a (ajouter)
313
Gilles Quenot

Notez la syntaxe standard sed (comme dans POSIX, donc prise en charge par toutes les implémentations sed conformes autour de (GNU, OS/X, BSD, Solaris ...)):

sed '/CLIENTSCRIPT=/a\
CLIENTSCRIPT2="hello"' file

Ou sur une ligne:

sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file

(-expressions (et le contenu de -files) sont joints à des nouvelles lignes pour constituer le script sed interprété par sed).

L'option -i pour l'édition sur place est également une extension GNU, d'autres implémentations (comme celles de FreeBSD) supportent -i '' pour cela.

Alternativement, pour la portabilité, vous pouvez utiliser Perl à la place:

Perl -pi -e '$_ .= qq(CLIENTSCRIPT2="hello"\n) if /CLIENTSCRIPT=/' file

Ou vous pouvez utiliser ed ou ex:

printf '%s\n' /CLIENTSCRIPT=/a 'CLIENTSCRIPT2="hello"' . w q | ex -s file
42
Stephane Chazelas

Un logiciel compatible POSIX utilisant la commande s:

sed '/CLIENTSCRIPT="foo"/s/.*/&\
CLIENTSCRIPT2="hello"/' file
12
SLePort

La commande Sed qui fonctionne sur MacOS (au moins, OS 10) et Unix (c.-à-d. Ne nécessite pas générique comme celle de Gilles (actuellement acceptée), c'est le cas):

sed -e '/CLIENTSCRIPT="foo"/a\'$'\n''CLIENTSCRIPT2="hello"' file

Cela fonctionne dans bash et peut-être aussi dans d'autres shell qui connaissent le style de citation d'évaluation $ '\ n'. Tout peut être sur une ligne et travailler dans anciennes commandes/POSIX sed. Si plusieurs lignes peuvent correspondre à CLIENTSCRIPT = "foo" (ou votre équivalent) et que vous souhaitez uniquement ajouter la ligne supplémentaire la première fois, vous pouvez la retravailler comme suit: 

sed -e '/^ *CLIENTSCRIPT="foo"/b ins' -e b -e ':ins' -e 'a\'$'\n''CLIENTSCRIPT2="hello"' -e ': done' -e 'n;b done' file

(Cela crée une boucle après le code d’insertion de ligne qui ne fait que parcourir le reste du fichier, sans jamais revenir à la première commande sed).

Vous remarquerez peut-être que j'ai ajouté un '^ *' au motif correspondant au cas où cette ligne apparaîtrait dans un commentaire, disons, ou serait en retrait. Ce n'est pas parfait à 100%, mais couvre d'autres situations susceptibles d'être courantes. Ajustez au besoin ...

Ces deux solutions permettent également de contourner le problème (pour la solution générique d’ajouter une ligne) que si votre nouvelle ligne insérée contient des barres obliques inverses ou des esperluettes non échappées, elles seront interprétées par sed et ne seront probablement pas identiques, tout comme le \n . \0 serait la première ligne correspondante. Particulièrement utile si vous ajoutez une ligne qui provient d'une variable pour laquelle vous auriez sinon à tout échapper en premier en utilisant $ {var //} auparavant, ou une autre instruction sed, etc.

Cette solution est un peu moins compliquée dans les scripts (citer et\n n’est pas facile à lire), si vous ne voulez pas mettre le texte de remplacement de la commande a au début de la ligne si, disons, dans une fonction avec des lignes en retrait. J'ai profité du fait que $ '\ n' est évalué comme une nouvelle ligne par le shell, ce n'est pas dans les valeurs '\ n' entre guillemets simples.

Cela prend suffisamment de temps pour que je pense que Perl/awk pourrait gagner parce qu’il est plus lisible.

5
Breezer

J'ai récemment eu à gérer cela, mais pas seulement pour un fichier, mais pour plusieurs fichiers différents que je ne pouvais tout simplement pas traiter manuellement. Je devais donc trouver un script pour cela.

Téléchargement du script: kinglazy-autoinsert.sh

Utilisation:

kinglazy-autoinsert.sh (list_file) (pattern_file)

Explication des paramètres:

list_file = Ceci est le fichier qui contient le chemin absolu de la liste des fichiers que vous voulez éditer

pattern_file = Ceci est le fichier dans lequel vous spécifiez le motif (dans la première colonne) sous lequel vous voulez ajouter du nouveau texte. Le nouveau texte à ajouter sous le motif est spécifié dans la deuxième colonne. Et c'est à peu près tout!

Ce script vous fait gagner du temps et vous aide à faire le travail avec le moins d'effort possible.

Dépendances: Aucune

0
Blessed

J'avais une tâche similaire et je ne pouvais pas utiliser la solution Perl décrite ci-dessus.

Voici ma solution:

Perl -i -pe "BEGIN{undef $/;} s/^\[mysqld\]$/[mysqld]\n\ncollation-server = utf8_unicode_ci\n/sgm" /etc/mysql/my.cnf

Explication:

Utilise une expression régulière pour rechercher une ligne dans mon fichier /etc/mysql/my.cnf qui ne contient que [mysqld] et la remplace par

[mysqld] collation-server = utf8_unicode_ci

ajouter effectivement la ligne collation-server = utf8_unicode_ci après la ligne contenant [mysqld].

0
Caleb

La variante awk:

awk '1;/CLIENTSCRIPT=/{print "CLIENTSCRIPT2=\"hello\""}' file
0
Corentin Limier

Peut-être un peu tard pour poster une réponse à cela, mais j’ai trouvé certaines des solutions ci-dessus un peu lourdes. 

J'ai essayé le remplacement de chaîne simple dans sed et cela a fonctionné:

sed 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

& Le signe reflète la chaîne correspondante, puis vous ajoutez\n et la nouvelle ligne.

Comme mentionné, si vous voulez le faire sur place:

sed -i 's/CLIENTSCRIPT="foo"/&\nCLIENTSCRIPT2="hello"/' file

Autre chose. Vous pouvez apparier en utilisant une expression:

sed -i 's/CLIENTSCRIPT=.*/&\nCLIENTSCRIPT2="hello"/' file

J'espère que cela aide quelqu'un

0
siwesam