I have to find the ipv4 in a file.The problem is if there are other words on the same line as the IP the script wont print it.Here is my script:


if [ -e ip.txt ]
    grep -E '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$' ip.txt
    echo "file not found"

Now if I have something like this the script wont print the IP: text
  • Is the sample input you provide representative of all permutations? i.e. will the IP address always be the first word of the line? If not, please add any other input permutations that are possible, by editing your question.
    – Sparhawk
    Sep 7, 2019 at 13:30
  • Change it to grep -Eo (-o for only match) and rid the $ on the end of it, like this: grep -Eo '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' ip.txt Like Prvt_Yadv's solution below.
    – Adam D.
    Sep 8, 2019 at 1:24

4 Answers 4


Remove ^ and $ from the command and use -o flag of grep command i.e.:

grep -Eo '(^| )(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($|[[:space:]])'


echo 'some text and test' | grep -Eo '(^| )(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])($|[[:space:]])'

output is:

It will give spaces also try removing them using tr, like command1 | tr -d " ".

  • But that would match the in or in xserver-common_1.14.2.901-2_all.deb for instance. The OP mentions trying to find words. Sep 7, 2019 at 13:19
  • 1
    @StéphaneChazelas I think the w flag will work.
    – Prvt_Yadav
    Sep 7, 2019 at 15:44
  • It wouldn't for the first example as . is not a word character. It depends on what the OP's data may contain that we wouldn't want to be included. If there may be things like version numbers or SNMP OIDs, then -w wouldn't prevent them from being mistakenly considered as containing IP addresses. If there's not then -w might be find. grep -w '[0-9.]{7,}' may also be enough depending on what the data may contain. Sep 7, 2019 at 17:25
  • but how about ! ? by using -w this is still a valid ip Sep 9, 2019 at 11:14
  • @RobertDumbrava see the edit.
    – Prvt_Yadav
    Sep 9, 2019 at 19:18

^ and $ match respectively at the beginning and end of the line, so lines with those IP addresses are only matched if the IP address is both at the beginning and end of the line, that is if the IP address is the whole line.

Now, if you want to match on lines that contain an IP address as a whole word, where words are blank-delimited, you could use:

grep -E "(^|[[:blank:]])$n\.$n\.$n\.$n([[:blank:]]|\$)" ip.txt

(here also replacing those [0-9] with [0123456789] as [0-9] often matches a lot more than just 0123456789).

Note that grep outputs the lines that match. If you want to only output parts of the lines, you'd need to use things like sed or perl instead (stream editors), or use some non-standard extensions of some grep implementations like the -o of GNU grep.

Here using negative look-around operators ((?<!\H) meaning "provided it's not preceded by a non-blank", (?!\H) same but looking forward instead of behind, (?1) recalls the RE in the first (...) group, all perl-like operators enabled with -P:

grep -Po '(?<!\H)(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.(?1)\.(?1)\.(?1)(?!\H)' ip.txt

Which would be an equivalent of:

perl -lne 'print for
  • You should try testing your answers, none of these ideas worked for me.
    – Adam D.
    Sep 8, 2019 at 10:39
  • @A.Danischewski you're right, it was pretty sloppy of me. It should be better now. Sep 8, 2019 at 14:14

To print only the IPv4's you could extract what is matched with the -o option to grep.

As a simpler example, you can do:

$ echo "this is a simple test to extract as an IP" | 
       grep -o '[0-9.]*'

But that will fail to precisely match one IPv4.

To match an IP is somewhat complex with a regex. A regex do not understand numeric ranges, only text. We can match one numeric 0-255 value with (a regex that ignore spaces and comments):

25[012345]                       | # the numers 250 - 255 or
2[01234](?P<digit>[0123456789])  | # 200 - 249 or
1(?&digit){2}                    | # 100 - 199 or
#0?                                 # Allow leading zero
[1-9](?&digit)                   | #  10 -  99 or
#0{0,2}                             # Allow leading zeros
(?&digit)                          #   0 - 9

Remove the first column comments to include leading zeros.

To avoid the repetition of [0-9], to use explicit numeric ranges (avoid matching numbers in other languages) and to give a name to each matching group we can use "Named Capture Groups" from PCRE's:

(?P<byte>                             # Define this as one full byte value.
25[012345]                          | # the numers 250 - 255 or
2[01234](?P<digit>[0123456789])     | # 200 - 249 or
1(?&digit){2}                       | # 100 - 199 or
#0?                                    # Allow leading zero
[1-9](?&digit)                      | #  10 -  99 or
#0{0,2}                               # Allow leading zeros
(?&digit)                             #   0 - 9
)                                     # close one full byte definition

Then we just need to repeat the use of the byte definition with a leading dot (\.(?&byte)){3} three more times and some leading and trailing markers as shown in this link

The leading and trailing markers could be simpler "word boundaries" (\b) if that is what is needed as shown in this other link

In the shell, with grep PCRE regex, the command could be written as:

$ grep -oP '(?xm)(?<=^|[^01234567890.])(?P<byte>25[012345]|2[01234](?P<digit>[0123456789])|[01]?(?&digit){1,2})(\.(?&byte)){3}(?=[^01234567890.]|$)' <<<"$a"

Given that the test string contains:

$ a='
text more text
text123.234.34.123more text
not in
not in xserver-common_1.14.2.901-2_all.deb'

This regex will grab the ip address and is a fairly accurate regex for IPv4 addresses, grep -P turns on PCRE regex engine and -o only returns the matching text:

grep -Po '\b((?:25[0-5]|[2][0-4][0-9]|[1][0-9]{2}|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|[2][0-4][0-9]|[1][0-9]{2}|[1-9][0-9]|[0-9])\b' ip.txt

For an explanation of this regex see this: https://regexr.com/4kjg4

25[0-5]          | # 250 - 255 
[2][0-4][0-9]    | # 200 - 249 
[1][0-9]{2}      | # 100 - 199 
[1-9][0-9]       | #  10 - 99
[0-9]            | #   0 - 9
  • The OP already has a regexp to match quad-decimal IPv4 addresses (yours also include some octal-based ones like, another wording for google's but doesn't allow 0377.0377.0377.0377 as an equivalent of They're asking about how to find IP addresses as words in the input. Sep 7, 2019 at 17:28
  • Updated, now it grabs only IPv4 words.
    – Adam D.
    Sep 8, 2019 at 1:52
  • @StéphaneChazelas It is known that interpreting IPv4 dotted addresses as octal leads to problems and there is known use of full 3 digits (with leading zeros) in RFCs
    – user232326
    Sep 8, 2019 at 4:08
  • @Isaac [Page 7] A 32-bit IPv4 address is divided into four octets. Each octet is represented numerically in decimal, using the minimum possible number of digits (leading zeroes are not used, except in the case of 0 itself). The four encoded octets are given most-significant first, separated by period characters.
    – Adam D.
    Sep 8, 2019 at 10:32
  • @Isaac IPv4address = d8 "." d8 "." d8 "." d8 d8 = DIGIT ; 0-9 / %x31-39 DIGIT ; 10-99 / "1" 2DIGIT ; 100-199 / "2" %x30-34 DIGIT ; 200-249 / "25" %x30-35 ; 250-255
    – Adam D.
    Sep 8, 2019 at 10:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.