Your issue has to do with the greediness of .*. You can still do it in sed, but it's easier with Perl:
$ echo 'range 1.1.1.10 1.1.1.100;' | perl -ne 'printf("IP range is %d-%d\n", (/\.(\d+)[^.]/g))' IP range is 10-100
The Perl script matches the numbers at the end of the IP addresses and returns these as two integers which are used in printf() to print the formatted output string.
The Perl regular expression
/\.(\d+)[^.]/g
will capture each set of digits preceded by a dot, but not followed by a dot.
In sed you don't really have to do the substitution in one go:
$ echo 'range 1.1.1.10 1.1.1.100;' | sed -E -e 's/[^ ]*\.([0-9]+);/\1/' range 1.1.1.10 100 $ echo 'range 1.1.1.10 1.1.1.100;' | sed -E -e 's/[^ ]*\.([0-9]+);/\1/' -e 's/[^ ]*\.([0-9]+) /\1-/' range 10-100 $ echo 'range 1.1.1.10 1.1.1.100;' | sed -E -e 's/[^ ]*\.([0-9]+);/\1/' -e 's/[^ ]*\.([0-9]+) /\1-/' -e 's/range/IP & is/' IP range is 10-100
The final sed script:
s/[^ ]*\.([0-9]+);/\1/; # Isolate last number in range s/[^ ]*\.([0-9]+) /\1-/; # Isolate first number in range, add dash s/range/IP & is/; # Sort out text at start
Which, upon inspection, can be shortened down to
s/[^ ]*\.([0-9]+)[^.]/-\1/g s/range -/IP range is /
That is
$ echo 'range 1.1.1.10 1.1.1.100;' | sed -E -e 's/[^ ]*\.([0-9]+)[^.]/-\1/g' -e 's/range -/IP range is /' IP range is 10-100
sedis doing exactly what you instruct it to do. Due to the greedy nature of regex the.*in.*([0-9]{1,3});will match up to (and not including) the last digit before the;so either introduce a literal dot like in your 1st command e.g..*\.([0-9]{1,3});or rethink your regex. And btw, disabling printing to explicitly print afterwards doesn't make much sense...