bashで文字列がIPアドレスかどうか判定する

bashの正規表現で文字列がIPアドレスか判定する。

IPv4とIPv6。IPv6は参考有り。使っている正規表現はPOSIX ERE

IPv4

192.168.0.1などのIPv4形式から:

str=192.168.0.1
if [[ "${str}" =~ ^(([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])$ ]]; then
    echo "${str} is an IPv4 address."
fi

一部のCIDR表記に対応する場合(/24などの付与):

str=192.168.0.1/24
if [[ "${str}" =~ ^(([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])(\/([1-9]|[1-2][0-9]|3[0-2]))?$ ]]; then
    echo "${str} is an IPv4 address with CIDR notation"
fi

IPv6

こちらはあんまり使わないので、フォーマットの多少の種類しか知らない。なので、調べたものを使う。

調べると、こちらがヒットした。

Regular expression that matches valid IPv6 addresses
I'm having trouble writing a regular expression that matches valid IPv6 addresses, including those in their compressed f...

0の省略と、リンクローカルアドレス、IPv4アドレスの埋め込みに対応しているようだ。 行頭、行末オペレータを追加して使えるようになる:

str=2001:0db8:3456::1
if [[ "${str}" =~ ^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$ ]]; then
    echo "${str} is an IPv6 address"
fi

IPv6のCIDR表記対応もIPv4と同じ。

str=2001:0db8:3456::1/32
if [[ "${str}" =~ ^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))(\/(1[0-1][0-9]|12[0-8]|[1-9][0-9]|[1-9]))?$ ]]; then
    echo "${str} is an IPv6 address with CIDR notation"
fi

おわり

IPv6は短縮について何通りも表現できてしまうので、対応する正規表現を作るのは大変。IPv4はだいぶ簡単だが、CIDR表記には、10.0.0.0/2410/24に省略するなどの表記法もあるようだ。それには対応していないので、留意したい。

bashでのチェックはたまに行いたくなるときがあるので、今回メモを残しておくことにした。

以上です。

タイトルとURLをコピーしました