Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find and replace every match except the first using sed?

Tags:

sed

I am using sed to find and replace text, e.g.:

set -i 's/a/b/g' ./file.txt

This replaces every instance of a with b in the file. I need to add an exception, such that sed replaces every instance of a with b, except for the first appearance in the file, e.g.:

There lived a bird who liked to eat fish.
One day he fly to a tree.

This becomes:

There lived a bird who liked to ebt fish.
One dby he fly to b tree.

How can I modify my sed script to only replace every instance of a with b, except for the first occurrence?

I have GNU sed version 4.2.1.

like image 377
Village Avatar asked Dec 16 '22 18:12

Village


2 Answers

This might work for you (GNU sed):

sed 's/a/b/2g' file

or

sed ':a;s/\(a[^a]*\)a/\1b/;ta' file

This can be taylored e.g.

sed ':a;s/\(\(a[^a]*\)\{5\}\)a/\1b/;ta' file

will start replacing a with b after 5 a's

like image 56
potong Avatar answered May 06 '23 09:05

potong


You can do a more complete implementation with a script that's more complex:

#!/bin/sed -nf

/a/ {
    /a.*a/ {
        h
        s/a.*/a/
        x
        s/a/\n/
        s/^[^\n]*\n//
        s/a/b/g
        H
        g
        s/\n//
    }

    : loop
    p
    n
    s/a/b/g
    $! b loop
}

The functionality of this is easily explained in pseudo-code

if line contains "a"
    if line contains two "a"s
        tmp = line
        remove everything after the first a in line
        swap tmp and line
        replace the first a with "\n"
        remove everything up to "\n"
        replace all "a"s with "b"s
        tmp = tmp + "\n" + line
        line = tmp
        remove first "\n" from line
    end-if

    loop
        print line
        read next line
        replace all "a"s with "b"s
        repeat loop if we haven't read the last line yet
    end-loop
end-if
like image 41
Janito Vaqueiro Ferreira Filho Avatar answered May 06 '23 10:05

Janito Vaqueiro Ferreira Filho