sed: delete items between multiple pattern matches (issue with greediness)

99 views Asked by At

So Ive spent a few hours looking at similar articles - helpful yes but not enough to get me over the hump.

I have a line I want to keep the beginning of and then surgically isolate matching patterns after to the end of the string.

For example heres the original line (easy to focus on just one line):

ltm pool gateway_ping { description "healthcheck pool" load-balancing-mode least-connections-node members { 10.100.100.4:icmp { address 10.100.100.4 session monitor-enabled state up } server2name:https { address 1.1.1.1 session monitor-enabled state up } } monitor Pingmonitor

This shortens and isolates the name like Im trying:

cat config.txt | sed -e 's/^ltm \(pool .*\) { .*members { /\1 members /'

gets me this:

pool gateway_ping members 10.100.100.4:icmp { address 10.100.100.4 session monitor-enabled state up } server2name:https { address 1.1.1.1 session monitor-enabled state up } } monitor Pingmonitor

Now to pipe the results to another sed and somehow get rid of anything between the each instance of braces

{ address 10.100.100.4 session monitor-enabled state up }
{ address 1.1.1.1 session monitor-enabled state up }

adding this:

| sed -e 's/{ address .* } / /g'

I ended up with this haircut giving me the first match correctly but blowing out all the rest:

pool gateway_ping members 10.100.100.4:icmp monitor Pingmonitor }

I really need the other members in there - the line should read:

pool gateway_ping members 10.100.100.4:icmp server2name:https monitor Pingmonitor }

I can get rid of the monitor Pingmonitor } Im just stuck on how to NOT have SED be greedy and blow out all matches to the very LAST end brace... I'd like it to stop at the first end brace... then continue on matching individually.

I think I may have murdered this by trying to describe it. Hopefully I didnt lose the audience :-)

2

There are 2 answers

2
sseLtaH On

Using sed

$ sed 's/[^ ]* \([^{]*\).*\(members\) {\([0-9.]*[^{]*\)[^}]*}\([^{]*\).*} \(}\)\(.*\)/\1\2\3\4\6 \5/' file
pool gateway_ping members 10.100.100.4:icmp  server2name:https  monitor Pingmonitor }
1
Kaffe Myers On
var='ltm pool gateway_ping { description "healthcheck pool" load-balancing-mode least-connections-node members { 10.100.100.4:icmp { address 10.100.100.4 session monitor-enabled state up } server2name:https { address 1.1.1.1 session monitor-enabled state up } } monitor Pingmonitor'

# with GNU awk
awk -F' *{ *' '
    /^ltm pool/{
        $0 = gensub(/^ltm (pool \w+) .* (members) {/, "\\1 \\2", "1")
        for(i=2; i<=NF-1; i++) sub(/.* /, "", $i)
        sub(/ address.*} }/, "")
    }
    ($1=$1)
' <<<"${var}"

### output:
pool gateway_ping members 10.100.100.4:icmp server2name:https monitor Pingmonitor

# with GNU sed
sed -nE '
    s/ \{ address( \S+){5} \}//g
    s/ +\}//;s/^ltm (pool \S+) \{ .* (members) \{/\1 \2/p
' <<<"${var}"

### output:
pool gateway_ping members 10.100.100.4:icmp server2name:https monitor Pingmonitor

Does any of these help you out? I can come back and edit the answer with some explanation if you want.