1
str="I want to abc replace a word abc in a sentence abc of file abc by giving abc specifying a abc multiple abc range to abc the sed abc command abc."

The above sting str has word "abc" 10 times occured,I want to replace "abc" occured from 2nd-4th time and 6th-8th with word "xyz" using sed command.

after sed command on string str ,str should look as below:

str="I want to abc replace a word xyz in a sentence xyz of file xyz by giving abc specifying a xyz multiple xyz range to xyz the sed abc command abc."
  • Does it have to be sed? – heemayl Feb 2 '15 at 10:34
  • Yes am looking specific to sed,if any other simpler and shorter way is there let me know. – Prashant BJ Feb 2 '15 at 17:19
2

I'm not sure if it's clever or not but here is my GNU sed solution:

sed 's/abc/nonABC/5;s/abc/nonABC/8g;s/abc/xyz/2g;s/nonABC/abc/g' <<<"$str"

Explanation:

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

And with awk and of course clever:

awk '{printf ( 2<=NR && NR<=8 && NR!=5 )?$0"xyz":$0RS}' RS='abc' <<<"$str"

Explanation:

  • RS='abc' defines 'abc' as Record Separator
  • if Number of Record was between 2 and 8 2<=NR && NR<=8 but not equal with 5 NR!=5, then print the current record $0 and the replace word xyz, otherwise, print the record and abc itself. you can use $0"abc" in place of $0RS.

If your ranges are like: [(2-4),(8-10),(12-15),(18-20),(26-29) ...] as you mentioned in comment then awk is best command for this job. Only you need is specifying the ranges as multiple condition:

( (2<=NR && NR<=4) || (8<=NR && NR<=10) || (12<=NR && NR<=15) || (18<=NR && NR<=20) || (26<=NR && NR<=29) || (...) )
  • @Kasiya-Both answers seems good,but if the file/string is large and the ranges are more we still need an efficient solution. Solution like just specifying ranges to sed/awk command, ranges like: [(2-4),(8-10),(12-15),(18-20),(26-29) .....] – Prashant BJ Feb 4 '15 at 18:30
  • yes for such cases awk is best. – Prashant BJ Feb 5 '15 at 18:34
  • @PrashantBJ please see my another answer posted here – αғsнιη Mar 23 '18 at 7:20
2

Another way with the helping of brace expansion, you can do:

sed '-es/abc/xyz/'{8..6} '-es/abc/xyz/'{4..2} <<<"$str"

Please note that range should be always max first in {max#..min#} even first max ranges should be specify at first.

You can also specify which positions range should replace in {x,y,z} format, where numbers should be x>y>z:

sed '-es/abc/xyz/'{8,6,4,2} <<<"$str"

Note that if you use same number {x,x} it will cause a problem and will replace position x again and again (BTW for this there is s/abc/xyz/X alternative where X is position number).


I learned this with from Stéphane Chazelas's answer on Unix.SE

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.