How to replace every nth occurrence of pattern using sed ONLY

I have searched all over the web but i can't find any good solutions. I have read on many forums that sed is not the tool (but awk is) for this but it makes no sense to me why. I mean you can do a simple substitution for occurrence number 5 for example like: sed 's/pattern/replace/5' to replace only the 5th instance. Why can't sed do 's/pattern/replace/<every 5th occur>' for one line? Isn't that a basic function..

Anyway my problem is that our client's software runs on a windows environment that has limited linux functions and unfortunately awk is not available on the system. Installing new commands is NOT an option for the company for whatever reason.

So my question is, what is the best way to use sed and/or mixed with bash for replacing every nth occurrence of a pattern per line? I only have one line anyway as i already stripped all the new line characters. Is bash for loop the only way?

1

2 Answers

Isn't that a basic function..

Obviously, it isn't. But it's still possible:

sed 's/a\([^a]*\($\|a[^a]*\($\|a[^a]*\($\|a[^a]*\($\|a\)\)\)\)\)/A\1/g'

More readable with -r where we can drop the backslashes:

sed -r 's/a([^a]*($|a[^a]*($|a[^a]*($|a[^a]*($|a)))))/A\1/g' 

i.e. a, followed by any number of non-a, followed by either end of line, or another a, followed by any number of non-a, etc. Everything after the first a is remembered in \1.

BTW, if Perl is available, you can use:

perl -pe 'BEGIN { @A = qw(a A) } s/a/$A[not $i++ % 5]/g'

% is the modulo operator. $i is incremented with each match, negation of the modulo is 1, 0, 0, 0, 0, 1, etc., which used as the index into @A picks the correct a or A.

7

Simple sed and a brace expansion:

sed '-es/pattern/replace/'{max..min..step} infile

replace max with a number >=number of occurrences of pattern, if you don't know that, set it as a largest number of characters in a longest line in your file.


$ sed '-es/a/A/'{20..1..5} <<<"aaaa aaaa a a a aa a a a aa aa"
aaaa Aaaa a A a aa a A a aa aA

To replace first occurrence too, use below:

$ sed '-es/a/A/'{{20..1..5},1} <<<"aaaa aaaa a a a aa a a a aa aa"
Aaaa Aaaa a A a aa a A a aa aA
1

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

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

You Might Also Like