0

I've got a bash variable containing several lines of text, which includes IP addresses, and I need to remove 'everything' before the last IP address occurrence in the same line.

This:

43.12.40.53 refunds@example.uk
archery-666.foobar.com  66.77.11.44 data test@example
55.32.39.153    remix@example.com
5.113.30.37 dummy
89-109-22-006.static.example.com.br 89.109.22.6 hello@example.com
68.28.15.55 68.28.15.55 another

should be transform into:

43.12.40.53 refunds@example.uk
66.77.11.44 data test@example
55.32.39.153    remix@example.com
5.113.30.37 dummy
89.109.22.6 hello@example.com
68.28.15.55 another

Reading this post How can I delete everything until a pattern and everything after another pattern from a line? I tried:

var=$(sed 's/^.*\(([0-9]{1,3}[\.]){3}[0-9]{1,3}\).*$/\1/' <<< "$var")

but it doesn't work.

2 Answers2

2

A couple of issues:

  1. you're mixing BRE and ERE (for example \( versus ( for the grouping)

  2. your .* at the end needs to be inside the capture group if you want the result to include everything after the IP

  3. the ^.* at the beginning will greedily consume as many characters as it can - including all but one of the leading IP digits

Also, . doesn't need to be escaped inside [] - although that doesn't break anything.

I'm not sure the RIGHT way to deal with (3) in sed which (unlike perl say) doesn't have a non-greedy modifier. Adding a word-boundary anchor \b seems to work but feels fragile

So either (BRE)

sed 's/^.*\(\b\([0-9]\{1,3\}[.]\)\{3\}[0-9]\{1,3\}.*$\)/\1/' <<< "$var"

or (ERE)

sed -E 's/^.*(\b([0-9]{1,3}[.]){3}[0-9]{1,3}.*$)/\1/' <<< "$var"
steeldriver
  • 81,074
1

You have correctly escaped the 1st parentheses, but not the second and not the {} which also need escaping. Also, you are matching everything to the end of the line (.*$) which isn't needed. Using your regex, this would do what you want:

$ sed 's/^.*\(\([0-9]\{1,3\}[\.]\)\{3\}[0-9]\{1,3\}\)/\1/' <<< "$var"
3.12.40.53 refunds@example.uk
6.77.11.44 data test@example
5.32.39.153    remix@example.com
5.113.30.37 dummy
9.109.22.6 hello@example.com
8.28.15.55 another

But this is still more complicated than necessary. For example, you don't need [\.], a simple \. is enough. And you can use the -E flag to enable extended regular expressions and simplify your syntax to:

$ sed -E 's/^.*(([0-9]{1,3}\.){3}[0-9]{1,3})/\1/' <<< "$var"
3.12.40.53 refunds@example.uk
6.77.11.44 data test@example
5.32.39.153    remix@example.com
5.113.30.37 dummy
9.109.22.6 hello@example.com
8.28.15.55 another

However, as steeldriver points out, your leading .* might eat up more than you expect, so it would be safer to do the whole thing in perl instead:

$ perl -pe 's/^.*?(([\d]{1,3}\.){3}\d{1,3})/\1/' <<< "$var"
43.12.40.53 refunds@example.uk
66.77.11.44 data test@example
55.32.39.153    remix@example.com
5.113.30.37 dummy
89.109.22.6 hello@example.com
68.28.15.55 68.28.15.55 another
terdon
  • 242,166