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!
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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;
}
Method 2
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 | validIP4echo 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.
Method 3
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.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0