Un aperçu des nombreuses réponses utiles existantes , complété par des explications :
Les exemples ici utilisent un cas d'utilisation simplifié: remplacez le mot «foo» par «bar» dans la première ligne correspondante uniquement.
En raison de l' utilisation de la norme ANSI chaînes C-cités ( $'...'
) pour fournir des lignes d'entrée échantillon, bash
, ksh
, ou zsh
est supposé que la coquille.
GNU sed
uniquement:
La réponse de Ben Hoffstein nous montre que GNU fournit une extension à la spécification POSIX car ellesed
permet la forme à 2 adresses suivante : 0,/re/
( re
représente ici une expression régulière arbitraire).
0,/re/
permet également à l'expression régulière de correspondre sur la toute première ligne . En d'autres termes: une telle adresse créera une plage de la 1ère ligne jusqu'à et y compris la ligne qui correspond re
- qu'elle re
se produise sur la 1ère ligne ou sur toute ligne suivante.
- Comparez cela avec le formulaire compatible POSIX
1,/re/
, qui crée une plage qui correspond de la 1ère ligne jusqu'à et y compris la ligne qui correspond re
sur les lignes suivantes ; en d'autres termes: cela ne détectera pas la première occurrence d'une re
correspondance s'il se produit sur la 1ère ligne et empêche//
également l'utilisation de sténographie pour la réutilisation de l'expression régulière la plus récemment utilisée (voir point suivant). 1
Si vous combinez une 0,/re/
adresse avec un s/.../.../
appel (substitution) qui utilise la même expression régulière, votre commande n'effectuera effectivement la substitution que sur la première ligne correspondante re
.
sed
fournit un moyen pratique raccourci pour réutiliser l'expression régulière plus récemment appliquée : un vide paire delimiter,//
.
$ sed '0,/foo/ s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
Un POSIX-fonctionnalités uniquement sed
telles que BSD (macOS)sed
(fonctionnera également avec GNU sed
):
Puisqu'il 0,/re/
ne peut pas être utilisé et que le formulaire 1,/re/
ne détectera pas re
s'il se produit sur la toute première ligne (voir ci-dessus), une gestion spéciale pour la 1ère ligne est requise .
La réponse de MikhailVS mentionne la technique, mise dans un exemple concret ici:
$ sed -e '1 s/foo/bar/; t' -e '1,// s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
Remarque:
Le //
raccourci d' expression régulière vide est utilisé deux fois ici: une fois pour le point d'extrémité de la plage, et une fois dans l' s
appel; dans les deux cas, l'expression régulière foo
est implicitement réutilisée, ce qui nous permet de ne pas avoir à la dupliquer, ce qui rend le code plus court et plus facile à maintenir.
POSIX a sed
besoin de nouvelles lignes après certaines fonctions, comme le nom d'une étiquette ou même son omission, comme c'est le cas t
ici; Le fractionnement stratégique du script en plusieurs -e
options est une alternative à l'utilisation d'un retour à la ligne réel: terminez chaque -e
bloc de script là où un retour à la ligne devrait normalement aller.
1 s/foo/bar/
remplace foo
uniquement sur la 1ère ligne, s'il y est trouvé. Si c'est le cas, se t
ramifie à la fin du script (ignore les commandes restantes sur la ligne). (La t
fonction se branche sur une étiquette uniquement si l' s
appel le plus récent a effectué une substitution réelle; en l'absence d'une étiquette, comme c'est le cas ici, la fin du script est branchée sur).
Lorsque cela se produit, l'adresse de plage 1,//
, qui trouve normalement la première occurrence à partir de la ligne 2 , ne correspondra pas et la plage ne sera pas traitée, car l'adresse est évaluée lorsque la ligne actuelle est déjà 2
.
Inversement, s'il n'y a pas de correspondance sur la 1ère ligne, 1,//
sera entré et trouvera la vraie première correspondance.
L'effet net est le même que celui avec GNU sed
de 0,/re/
: seule la première occurrence est remplacée, si elle se produit sur la 1ère ligne ou tout autre.
Approches sans portée
la réponse de potong démontre des techniques de boucle qui contournent le besoin d'une gamme ; puisqu'il utilise la syntaxe GNU sed
, voici les équivalents compatibles POSIX :
Technique de boucle 1: lors de la première correspondance, effectuez la substitution, puis entrez une boucle qui imprime simplement les lignes restantes telles quelles :
$ sed -e '/foo/ {s//bar/; ' -e ':a' -e '$!{n;ba' -e '};}' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
Technique de boucle 2, pour les petits fichiers uniquement : lisez l'intégralité de l'entrée en mémoire, puis effectuez une seule substitution dessus .
$ sed -e ':a' -e '$!{N;ba' -e '}; s/foo/bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
1 1.61803 donne des exemples de ce qui se passe avec 1,/re/
, avec et sans suite s//
:
- sed '1,/foo/ s/foo/bar/' <<<$'1foo\n2foo'
rendements $'1bar\n2bar'
; c'est-à-dire que les deux lignes ont été mises à jour, car le numéro de ligne 1
correspond à la 1ère ligne, et l'expression régulière /foo/
- la fin de la plage - n'est alors recherchée qu'à partir de la ligne suivante . Par conséquent, les deux lignes sont sélectionnées dans ce cas et la s/foo/bar/
substitution est effectuée sur les deux.
- sed '1,/foo/ s//bar/' <<<$'1foo\n2foo\n3foo'
échoue : avec sed: first RE may not be empty
(BSD / macOS) et sed: -e expression #1, char 0: no previous regular expression
(GNU), car, au moment où la 1ère ligne est traitée (en raison du numéro de ligne 1
commençant la plage), aucune expression régulière n'a encore été appliquée, donc//
ne fait référence à rien.
À l'exception de sed
la 0,/re/
syntaxe spéciale de GNU , toute plage commençant par un numéro de ligne empêche effectivement l'utilisation de //
.