Não tenho certeza se é inteligente ou não, mas aqui está minha solução de sed do GNU:
sed 's/abc/nonABC/5;s/abc/nonABC/8g;s/abc/xyz/2g;s/nonABC/abc/g' <<<"$str"
Explicação:
sed '
s/abc/nonABC/5; # replace only 5th occurrence of 'abc' word with another word (i, e: 'nonABC')
s/abc/nonABC/8g; # replace 8th to the next occurrences of 'abc' with another word too
s/abc/xyz/2g; # replace all occurrences of 'abc' word start from 2th place
s/nonABC/abc/g # get back the all changed 'abc' from 'nonABC'
' <<<"$str" # from 'str' as input
E com awk
e, claro, inteligente:
awk '{printf ( 2<=NR && NR<=8 && NR!=5 )?$0"xyz":$0RS}' RS='abc' <<<"$str"
Explicação:
-
RS='abc'
define 'abc' como R ecord S eparator - se N umber de R ecord estiver entre 2 e 8
2<=NR && NR<=8
, mas não igual a 5NR!=5
, imprima o registro atual$0
e substitua a palavraxyz
, caso contrário, imprima o registro eabc
em si. você pode usar$0"abc"
no lugar de$0RS.
Se os seus intervalos forem semelhantes: [(2-4), (8-10), (12-15), (18-20), (26-29) ...] como você mencionou no comentário então awk
é o melhor comando para este trabalho. Só você precisa especificar os intervalos como várias condições:
( (2<=NR && NR<=4) || (8<=NR && NR<=10) || (12<=NR && NR<=15) || (18<=NR && NR<=20) || (26<=NR && NR<=29) || (...) )