6
echo "1.1.1.1" | awk '/[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*/ {print $1}'

How can I filter IPv4 addresses in a script, and how can I filter IPv6 addresses.

I mean more precisely then this so the oneliner should only output VALID IPv4 addresses or another script to output only VALID IPv6 addr. In different languages? like: awk, perl?

ty!

2
  • What exactly do you consider valid? Is 241.57.97.2 valid (it's in an unassigned range)? What about 198.51.100.2 (it's reserved for documentation)? Are 6-to-4 IPv6 addresses to be considered valid IPv6 addresses? – Gilles 'SO- stop being evil' Aug 28 '11 at 17:43
  • yes, there are VALID too! :) – LanceBaynes Aug 28 '11 at 17:46
6

There are several usual notations for IPv4 and IPv6 addresses. Here's an extended regular expression, suitable for Perl m//x, that captures the usual notations. If you remove the comments and whitespace, you can use it with grep -E, awk, or any other utility that uses extended regular expressions (ERE).

^(
  ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]|0+[0-3][0-7][0-7]|0x0*[0-9a-fA-F][0-9a-fA-F])
  (\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]|0+[0-3][0-7][0-7]|0x0*[0-9a-fA-F][0-9a-fA-F])){3}   # IPv4 dotted quad
| 0x[0-9a-fA-F]{1-8}             # IPv4 hexadecimal
| 0+[0-9]{0-10} | 0+[1-3]{11}    # IPv4 octal
| [1-9][0-9]{1-8}                # IPv4 decimal, small
| [1-3][0-9]{9}                  # IPv4 decimal, medium
| 4[0-9]{9}                      # IPv4 decimal, large (needs a further range check)
| [0-9a-fA-F]{1-4}(:[0-9a-fA-F]{1-4}){7}            # IPv6 with all groups
| ([0-9a-fA-F]{1-4}:){1-1}(:[0-9a-fA-F]{1-4}){1-6}  # IPv6 with 1-6 middle groups omitted
| ([0-9a-fA-F]{1-4}:){1-2}(:[0-9a-fA-F]{1-4}){1-5}  # IPv6 with 1-6 middle groups omitted
| ([0-9a-fA-F]{1-4}:){1-3}(:[0-9a-fA-F]{1-4}){1-4}  # IPv6 with 1-6 middle groups omitted
| ([0-9a-fA-F]{1-4}:){1-4}(:[0-9a-fA-F]{1-4}){1-3}  # IPv6 with 1-6 middle groups omitted
| ([0-9a-fA-F]{1-4}:){1-5}(:[0-9a-fA-F]{1-4}){1-2}  # IPv6 with 1-6 middle groups omitted
| ([0-9a-fA-F]{1-4}:){1-6}(:[0-9a-fA-F]{1-4}){1-1}  # IPv6 with 1-6 middle groups omitted
)$

In case of a decimal value, you need a further range check (you can make a regexp of it, but it would be big):

if (!/[^0-9]/ && /^[^0]/) { # if it's a decimal number
    die if $_ > 4294967295 # reject numbers above 2^32-1
}

If the tool you use only supports 32-bit numbers, you can do the test only if the number starts with 4, and strip the 4 before doing the check.

if (!/[^0-9]/ && /^4/) { # if it's a decimal number beginning with 4
    my $tmp = $_;
    $tmp =~ s/^4//;
    die if $tmp > 294967295;
}
6
  • ...And you are not checking the range of values :) – rozcietrzewiacz Aug 28 '11 at 18:40
  • @rozcietrzewiacz I'm not? I wrote this quickly and didn't test it, so I may have made a mistake. What bad value gets through? I've made the test a bit more precise and added a way to test the range for decimals. – Gilles 'SO- stop being evil' Aug 28 '11 at 18:52
  • Oh, right - you are checking the range... Only you didn't add separators at the beginning and end, so things like 999.0.0.999 seem to pass. – rozcietrzewiacz Aug 28 '11 at 18:54
  • I'd add [^0-9] at the beginning and the end of each... – rozcietrzewiacz Aug 28 '11 at 19:01
  • 1
    Many may be baffled by the complexity of this regex, but there are yet many valid IPv4 and IPv6 formats missing, e.g. IPv4 n.n.nn and n.nnn, IPv6 with leading or ending :: (think localhost ::1), IPv4-mapped IPv6, etc. This answer is interesting as it leads to the same conclusion as on e-mail addr: regexes are OK (even naive ones like in the OP) to grep a log file (you'd better use some textual context so as to reduce the number of false positives); OTOH regexes are NOT the right tool to validate an IP address: instead use library functions offered by your language (like inet_xxx()) – xhienne Feb 27 at 11:21
0

In bash:

validIP4 () 
{ 
    IFS='.' read na nb nc nd;
    for n in "$na" "$nb" "$nc" "$nd";
    do
        [[ ${#n} -le 3 ]] && [[ "${n//[^0-9]/}" = "$n" ]] && [[ $n -lt 256 ]] || return 1;
    done
    echo OK
}

Usage examples:

  • echo 142.24.045.33 | validIP4
  • echo sd3.3.4.6 | validIP4 || echo "nope :("
  • echo 342.0.0.2 | validIP4 || echo "Noo...."
  • echo 3.2.1.0 | validIP4 && echo "Yes, sir."

As Gilles noted, this verifies only the most popular dot-decimal notation of an IPv4 address.

IPv6 can be done in a similar manner, but needs much more checking because (1) it uses hex and (2) some sections of all-zeros can be entirely omitted.

2
0

Extending Gilles' answer, his regular expression doesn't work for ActiveState Perl (version 5.20.3, Windows 7/64). According here, the quantifiers for the patterns from {num1-num2} has to be changed to {num1,num2} and it will worked.

Thank you for the REGEXP, it saves me to add the Data::Validate::IP module in on my Perl site.

2
  • If your answer extends another one, it is okay, if it contains enough information to be considered also an answer. I think your answer nears it. Note, collecting 50 rep will be much more easy as it seems. – peterh Jan 18 '18 at 0:09
  • I reformulated your post to become an induvidual answer, so it will likely survive the moderation vote. – peterh Jan 18 '18 at 0:14

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.