Est-il possible de faire correspondre plusieurs numéros de ligne spécifiques (pas de plage) avec sed?


9

Considérer:

echo -e "a\nb\nc\nd\ne\nf\ng\nh" | sed '3,5a test'

Cela correspondra aux lignes 3, 4 et 5.

Mais j'essaie de faire correspondre uniquement les lignes 3 et 5 (pas 4). Et ajoutez «test» après eux.

Réponses:


9
echo ... | sed -e '3a test' -e '5a test'

Si l'opération est plus complexe que dans ce cas, vous pouvez utiliser une structure comme celle-ci:

sed 'b pattern; : action; a \
lalala
b end; : pattern; 3b action; 5b action; : end'

C'est-à-dire que vous mettez toutes les commandes dont vous avez besoin entre b pattern;et b end;.

Et vous ajoutez tous vos modèles (numéros de ligne ou autre) après : pattern;.

Ce qui se passe est le suivant:

  1. La première commande saute sur la partie action (il est peut-être plus facile de lire si les motifs sont au début et b end;juste avant la partie action).

  2. Si un modèle correspond, l'exécution passe à la partie action. Après l'exécution, l'exécution de la partie passe à la fin.

J'essaye de ranger ça:

sed '3b action; 5b action; b end; : action; a \
lalala
: end'

En une seule ligne serait comme:

sed "3b idAction; 5b idAction; b; : idAction; a test"

Portablement, vous devez l'écrire:

sed '
   3b action
   5b action
   b
   : action
   a\
   lalala'

( bsans les branches d'étiquette à la fin, vous n'avez donc pas besoin d'une endétiquette explicite , ;c'est un caractère valide dans une étiquette dans les sedimplémentations standard ).


4
Wow, sous-programmes sed. Cool
Glenn Jackman

Wow en effet, pourriez-vous développer cela? Ils ont l'air vraiment utiles!
terdon

celui avec 'pattern' et 'action' semble très bon car je n'ai pas besoin de répéter 'test' (ou 'lalala'), je dois encore mieux le comprendre tho thx! :)
Aquarius Power

@terdon Que pourrais-je?
Hauke ​​Laging

Je voulais dire que le second était super mais difficile à comprendre et si vous avez le temps, j'apprécierais une explication.
terdon

5

Avec sed(voir la réponse de @ HaukeLaging )

Avec awk:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | awk 'NR==3 || NR==5{$0=$0"\ntest"}1;'

Avec perl:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | perl -pe '$_ .="test\n" if $. == 3 || $. == 5'

Peut jouer un peu à votre perl en utilisant l'opérateur "smart match":perl -lnE 'say if $. ~~ @{[3,5]}'
glenn jackman

@glennjackman ah, oui en effet, merci. Je dois admettre que je me méfie un peu ~~, je ne le comprends pas aussi bien que je le devrais. Aussi, les deux sayet ont ~~besoin de perl v> = 5.10 non?
terdon

Je dois ajouter «test» après ces lignes, je vois maintenant qu'il aurait mieux valu clarifier cela depuis le début. Je viens d'éditer l'OP.
Aquarius Power

@AquariusPower, perl -pE 'say "test" if $. ~~ @{[4,6]}'- ceci ajoute la ligne: perl -pfait une impression implicite à la fin du programme donné.
glenn jackman

@AquariusPower voir également la réponse mise à jour.
terdon

3

Comme l'a déjà dit @HaukeLaging, cette commande fait ce que vous voulez:

sed -e'3a test' -e'5a test'

Maintenant, cela peut devenir assez lourd à taper si vous voulez faire correspondre, par exemple, 20 lignes.

Dans ces cas, en supposant que votre shell prend en charge l' expansion d'accolade , vous pouvez utiliser cette commande à la place:

sed -e{3,5}'a test'

(Notez que les accolades et la virgule doivent rester sans guillemets.)

En conséquence, le shell passera les arguments à -e3a testet -e5a testà sed, ce qui est exactement ce que fait la première commande.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.