angelcool.net
angelcool.net

Reputation: 2546

Sed: apply substitution to captured group

I'm running the following command

find ./ -type f -exec sed -i -r "s/name='(REGEX)' value='REGEX'/name='\1' value='\1'/g" {} \;

The captured group \1 outputs something like:

MainCategory[ChildCategory][GrandchildCategory][GeatGrandchildCategory]

What I'm trying to do is replace (using the same sed command) all square brackets with periods in value only, the expected output would be:

name='MainCategory[ChildCategory][GrandchildCategory][GeatGrandchildCategory]' value='MainCategory.ChildCategory.GrandchildCategory.GeatGrandchildCategory'

Note: MainCategory depth is unknown.

I'm trying to avoid running another sed command. Any help/suggestions is appreciated.

Upvotes: 0

Views: 223

Answers (4)

Jonathan Leffler
Jonathan Leffler

Reputation: 755026

Working from the comments, it appears that if the input was (file data.in):

name='main[sub][subsub][least]' value='abs.nom.value'
name='MainCategory[ChildCategory][GrandchildCategory][GeatGrandchildCategory]' value='Diddly:Squat'

Then the desired output is (file data.out):

name='main[sub][subsub][least]' value='main.sub.subsub.least'
name='MainCategory[ChildCategory][GrandchildCategory][GeatGrandchildCategory]' value='MainCategory.ChildCategory.GrandchildCategory.GeatGrandchildCategory'

I would create a script in a file — I called it sed.1 — like this:

/name='\([^[]*\)\[\([^[]*\)]\[\([^[]*\)]\[\([^[]*\)]' value='[^']*'/{
    s//name='\1[\2][\3][\4]' value='\1.\2.\3.\4'/
}

I still use the original sed regex language when I can, and in this example, it works fine, albeit a bit verbosely. I could then run it with:

sed -f sed.1 data.in

The output is identical to data.out. This assumes you can modify your complex regex to capture the four segments in separate captures.

If your complex regex cannot be modified to recognize the four parts separately, then you can still achieve the desired result. For example (file sed.2):

/^name='\([^']*\)' value='[^']*'/{
    s//\1/
    h
    s/]\[/./g
    s/\[/./
    s/]//
    s/.*/value='&'/
    x
    G
    s/\(.*\)\n/name='\1' /
}

This too produces the desired output from the sample input.

Upvotes: 1

repzero
repzero

Reputation: 8402

find ./ -type f -exec sed -r -i.bak -e '/value='ANOTHER-COMPLEX-REGEX'/s/(\]\[|\]|\[)/./g' -e '/name='COMPLEX-REGEX'/s/(\]\[|\]|\[)/./g' {} \;

-i.bak make a backup of the original file with an extension .bak

COMPLEX-REGEX and ANOTHER-COMPLEX-REGEX - I am assuming these expression have the your square bracketed values.

Upvotes: 0

Avinash Raj
Avinash Raj

Reputation: 174844

Use basic sed like below.

sed 's/^\([^ ]*\) \(.*\)$/\2/;s/^\[\|\]$//g;s/\(\[\|\]\)\+/./g'

Example:

$ echo 'foo MainCategory[ChildCategory][GrandchildCategory][GeatGrandchildCategory]' | sed 's/^\([^ ]*\) \(.*\)$/\2/;s/^\[\|\]$//g;s/\(\[\|\]\)\+/./g'
MainCategory.ChildCategory.GrandchildCategory.GeatGrandchildCategory

Upvotes: 0

quantdev
quantdev

Reputation: 23813

sed accepts multiple expressions in the same call, just chain them with the -e option :

sed -i -r -e "s/name='(COMPLEX-REGEX)' value='ANOTHER-COMPLEX-REGEX'/name='\1'/g" -e "s/[][]/\./g"

Upvotes: 0

Related Questions