3

I have a sentence whic contains an IP address. For example,

This sentence contains an ip number 1.2.3.4 and port number 50, i want to print the IP address only.

From the above sentence, I want to print the IP address only. How can I do this? I heard that it is possible to do this with sed

7 Answers 7

7

It's possible, but not elegant:

echo 'This sentence contains an ip number 1.2.3.4 and port number 50, i want to print the IP address only.' \
| sed 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/'

[0-9] matches any digit, \{1,3\} means it can be repeated 1 to 3 times. \. matches a dot. The whole IP is captured by the \(...\) parentheses, what comes before and after is matched by .*, i.e. anything repeated zero or more times. The whole matching string (i.e. the whole line) is then replaced by the contents of the first matching group.

You can make it more readable by introducing a variable:

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

It prints the whole string if the IP is not found. It also doesn't check for invalid IPs like 256.512.999.666.

4
  • Could you please explain me how this works. It might help me more to learn sed. Nov 21, 2014 at 14:03
  • 1
    @AnanduMDas: Updated.
    – choroba
    Nov 21, 2014 at 14:07
  • One more help can you do? If I have a new line after this line, then that line is also getting printed. Can I force sed to check for the first line only? Nov 21, 2014 at 14:23
  • 1
    For multiline processing, I'd turn to Perl.
    – choroba
    Nov 21, 2014 at 14:46
6

This is a grep solution:

echo "$sentence" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'
  • -o print only the matching part
  • -E switches to extended regex
  • the pattern matches every digit ([0-9]) one or more times (+) then a dot (\.) and again digits...

Here another solution with perl:

echo "$sentence" | perl -l -ne '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ && print $&'
  • -l specified the line terminator (newline)
  • -n loops trough the input given by echo (could be multiple lines)
  • -e code follows
  • the regex inside the perl code is very much the same as in the grep solution above
8
  • @chaos wouldn't grep match any character for the ., given that you included the -E option?
    – skeggse
    Nov 21, 2014 at 15:28
  • @skeggse Ur right, I changed it, thanks for your note
    – chaos
    Nov 21, 2014 at 15:33
  • @AvinashRaj It a question of perfection. [0-9]{1,3} would match 987.567.432.999 too and that's not a valid ip address.
    – chaos
    Nov 21, 2014 at 15:36
  • @chaos yeah, but by that logic your regex matches 298724387956458376345.1.1.1, which is definitely not a valid ip address.
    – skeggse
    Nov 21, 2014 at 15:48
  • @skeggse "definitely not valid" and "not valid" is the same. Things can't be more invalid than other things. =)
    – chaos
    Nov 21, 2014 at 15:52
2

Use this command of grep:

grep -Eo '[0-9.]+ ' file

Or even better:

grep -oP '\d+\.\d+\.\d+\.\d+' file

or

grep -Eo "([0-9]{1,3}[\.]){3}[0-9]{1,3}" file
1

I use grep:

echo 'This sentence contains an ip number 1.2.3.4 and port number 50, i want to print the IP address only.' | grep -oE '((1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.){3}((1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]))'

This will print only valid ip adresses, unlike the other answers

0

I would do like this in python 3 interpreter. It not only grabs the text which are in this 111.111.111.111 format but also it checks for valid or not.

>>> import re
>>> import ipaddress
>>> text = "This sentence contains an ip number 1.2.3.4 and 111.111.111.111 451.976.897.786 port number 50, i want to print the IP address only."
>>> foo = re.findall(r'(?<!\S)(?:\d{1,3}\.){3}\d{1,3}(?!\S)', text)
>>> foo
['1.2.3.4', '111.111.111.111', '451.976.897.786']
>>> for i in foo:
...     try:
...         ipaddress.ip_address(i)
...     except:
...         pass
... 
IPv4Address('1.2.3.4')
IPv4Address('111.111.111.111')

To get the python 3 interpreter, type python3 command on the terminal.

0

Extension to choroba's answer:

If you don't want new line to be printed and you only want to print IP's:

$ echo -e 'This sentence contains an ip number 1.2.3.4 and port number 50, \ni want to print the IP address only.\n One more IP is 1.24.53.3.' \
| sed -n 's/.*\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\).*/\1/1p'

Output:

1.2.3.4
1.24.53.3

Explanation:

-n flag is for quiet / silent.
 p print the replaced text
0

AWK combined with RegExp is very appropriate for processing parts of lines.

Basic idea of the one-liner bellow is to for-loop through a line, and check for presence of four digits and dots, repeated at maximum 4 times; at the same time we can check for a digit repeated 2 to 4 times for port number

awk '{for(i=1;i<=NF;i++) { if ($i~/[[:digit:]\.]{4}/) printf $i; if ( $i~/[[:digit:]]{2,4}/) printf ":"$i  }}'

Sample run

$ echo "This sentence contains an ip number 1.2.3.4 and port number 50, i want to print the IP address only." |  awk '{for(i=1;i<=NF;i++) { if ($i~/[[:digit:]\.]{4}/) printf $i; if ( $i~/[[:digit:]]{2,4}/) printf ":"$i  }}'

1.2.3.4:50,

Your sentence contains 50 and, together without separation, hence printed together, but with gsub(/[[:punct:]]/,"") that can be removed if desired.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .