Pour une raison quelconque, je n'arrive pas à trouver une réponse simple à cela et je suis sur un peu de temps à l'heure actuelle. Comment pourrais-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 sed
commande. J'ai ...
CLIENTSCRIPT="foo"
CLIENTFILE="bar"
Et je veux insérer une ligne après la CLIENTSCRIPT=
ligne résultant en ...
CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"
sed
. Ce n'est pas unesed
syntaxe standard et ne fonctionnera avec aucune autresed
implémentation.Notez la
sed
syntaxe standard (comme dans POSIX, donc supportée par toutes lessed
implémentations conformes autour (GNU, OS / X, BSD, Solaris ...)):Ou sur une seule ligne:
(les
-e
xpressions (et le contenu des-f
fichiers) sont associés à des nouvelles lignes pour constituer lessed
interpréteurs de script sed ).L'
-i
option d'édition sur place est également une extension GNU, d'autres implémentations (comme FreeBSD) le supportent-i ''
.Alternativement, pour la portabilité, vous pouvez utiliser à la
perl
place:Ou vous pouvez utiliser
ed
ouex
:la source
sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file
échappe à la citation à la fin du premier paramètre et rompt la commande.csh
ourc
famille,'...'
sont des citations fortes à l'intérieur desquelles la barre oblique inversée n'est pas spéciale. La seule exception que je connaisse est lefish
shell.sed
n'est pas compatible POSIX ici. Cela rend ma déclaration sur le fait qu'il soit portable incorrect (pour la variante d'une ligne). Je vais demander à l'opengroup de confirmer s'il s'agit bien d'une non-conformité ou d'une mauvaise interprétation de la norme de ma part.Un conforme POSIX utilisant la
s
commande:la source
sed -e '/.../s/$/\' -e 'CLI.../'
ce qui éviterait des problèmes avec des lignes contenant des séquences d'octets ne formant pas de caractères valides.Commande Sed qui fonctionne sur MacOS (au moins, OS 10) et Unix (c.-à-d. Ne nécessite pas gnu sed comme celui de Gilles (actuellement accepté)):
Cela fonctionne dans bash et peut-être aussi dans d'autres shells qui connaissent le style de devis d'évaluation $ '\ n'. Tout peut être sur une seule ligne et fonctionner dans des commandes sed plus anciennes / POSIX. S'il peut y avoir plusieurs lignes correspondant à CLIENTSCRIPT = "foo" (ou votre équivalent) et que vous ne souhaitez ajouter la ligne supplémentaire que la première fois, vous pouvez la retravailler comme suit:
(cela crée une boucle après le code d'insertion de ligne qui fait simplement défiler le reste du fichier, sans jamais revenir à la première commande sed).
Vous remarquerez peut-être que j'ai ajouté un '^ *' au modèle correspondant au cas où cette ligne apparaît dans un commentaire, par exemple, ou est en retrait. Ce n'est pas parfait à 100% mais couvre d'autres situations susceptibles d'être courantes. Ajustez au besoin ...
Ces deux solutions contournent également le problème (pour la solution générique consistant à ajouter une ligne): si votre nouvelle ligne insérée contient des barres obliques inverses ou des esperluettes, elles seront interprétées par sed et ne sortiront probablement pas de la même manière, tout comme l'
\n
est - par exemple.\0
serait la première ligne correspondante. Particulièrement pratique si vous ajoutez une ligne qui provient d'une variable où vous auriez autrement à tout échapper en premier en utilisant $ {var //} avant, ou une autre instruction sed, etc.Cette solution est un peu moins compliquée dans les scripts (que les guillemets et \ n ne sont pas faciles à lire cependant), lorsque vous ne voulez pas mettre le texte de remplacement de la commande a au début d'une ligne, par exemple, dans une fonction avec des lignes en retrait. J'ai profité du fait que $ '\ n' est évalué à une nouvelle ligne par le shell, ce n'est pas dans des valeurs simples '\ n' entre guillemets.
Cela devient cependant assez long pour que je pense que perl / même awk pourrait gagner en raison de sa lisibilité.
la source
s/CLIENTSCRIPT="foo"/&\
[Entrée]CLIENTSCRIPT2="hello"/
. La barre oblique inversée doit être le tout dernier caractère de la ligne (pas d'espace après), contrairement à ce à quoi elle ressemble dans ce commentaire.s///
, ainsi que ceux des commandesa
eti
peuvent être "échappés", en utilisant la même méthode que je décris dans mon commentaire ci-dessus.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 simple des cordes dans sed et cela a fonctionné:
Le signe & reflète la chaîne correspondante, puis vous ajoutez \ n et la nouvelle ligne.
Comme mentionné, si vous souhaitez le faire sur place:
Autre chose. Vous pouvez faire correspondre en utilisant une expression:
J'espère que cela aide quelqu'un
la source
\n
dans la chaîne de remplacement. Plain-vanilla (POSIX)sed
ne comprend pas\n
dans la chaîne de remplacement, cependant, cela ne fonctionnera pas sur BSD ou macOS - à moins que vous n'ayez installé GNU sed d'une manière ou d'une autre. Avec vanilla sed, vous pouvez incorporer des sauts de ligne en les «échappant», c'est-à-dire en terminant la ligne par une barre oblique inverse, puis en appuyant sur [Entrée] ( référence , sous l'en-tête pour[2addr]s/BRE/replacement/flags
). Cela signifie que votre commande sed doit s'étendre sur plusieurs lignes dans le terminal.La variante awk:
la source
1;
, consultez Pourquoi le «1» dans awk imprime-t-il la ligne actuelle?J'ai eu une tâche similaire et je n'ai pas pu faire fonctionner la solution Perl 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 la contenait uniquement
[mysqld]
et l'a remplacée par[mysqld] collation-server = utf8_unicode_ci
ajouter efficacement la
collation-server = utf8_unicode_ci
ligne après la ligne contenant[mysqld]
.la source
J'ai dû le faire récemment pour les systèmes d'exploitation Mac et Linux et après avoir parcouru de nombreux messages et essayé beaucoup de choses, à mon avis, je ne suis jamais arrivé à l'endroit où je voulais ce qui est: une solution assez simple pour comprendre en utilisant bien connu et des commandes standard avec des motifs simples, une doublure, portable, extensible pour ajouter plus de contraintes. Ensuite, j'ai essayé de le regarder avec une perspective différente, c'est alors que j'ai réalisé que je pouvais me passer de l'option "un liner" si un "2 liner" répondait au reste de mes critères. À la fin, j'ai trouvé cette solution que j'aime et qui fonctionne à la fois sur Ubuntu et sur Mac que je voulais partager avec tout le monde:
Dans la première commande, grep recherche les numéros de ligne contenant "foo", cut / head sélectionne la 1ère occurrence, et l'op arithmétique incrémente ce premier numéro de ligne d'occurrence de 1 car je veux insérer après l'occurrence. Dans la deuxième commande, il s'agit d'une modification de fichier sur place, "i" pour l'insertion: un ansi-c citant une nouvelle ligne, "bar", puis une autre nouvelle ligne. Le résultat est l'ajout d'une nouvelle ligne contenant "bar" après la ligne "foo". Chacune de ces 2 commandes peut être étendue à des opérations et des correspondances plus complexes.
la source