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 zshest 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/( rerepré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 rese 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 resur les lignes suivantes ; en d'autres termes: cela ne détectera pas la première occurrence d'une recorrespondance 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.
sedfournit 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 sedtelles 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 res'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' sappel; dans les deux cas, l'expression régulière fooest 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 sedbesoin de nouvelles lignes après certaines fonctions, comme le nom d'une étiquette ou même son omission, comme c'est le cas tici; Le fractionnement stratégique du script en plusieurs -eoptions est une alternative à l'utilisation d'un retour à la ligne réel: terminez chaque -ebloc de script là où un retour à la ligne devrait normalement aller.
1 s/foo/bar/remplace foouniquement sur la 1ère ligne, s'il y est trouvé. Si c'est le cas, se tramifie à la fin du script (ignore les commandes restantes sur la ligne). (La tfonction se branche sur une étiquette uniquement si l' sappel 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 sedde 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 1correspond à 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 1commençant la plage), aucune expression régulière n'a encore été appliquée, donc//ne fait référence à rien.
À l'exception de sedla 0,/re/syntaxe spéciale de GNU , toute plage commençant par un numéro de ligne empêche effectivement l'utilisation de //.