2020/07/22

awk による IPv4 アドレスのマッチ処理

標準入力から入力されるテキストデータから IPv4 アドレスを awk(1) を利用して抽出する。
その際に CIDR 形式でないアドレスに関しては末尾に "/32" を付与して CIDR 形式にして出力する。

  1awk '{
  2    if(match($0, /([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(\/[[:digit:]]{1,2})?/))
  3        print match((ip = substr($0, RSTART, RLENGTH)), /\/[[:digit:]]{1,2}/) ? ip : ip "/32";
  4}'
    

1 行目の match() 関数で入力データから正規表現を利用して IPv4 アドレスを抽出し、 2 行目の substr() 関数を利用してマッチした範囲を切り出して IPv4 アドレスを変数 ip に格納している。 2 行目の match() 関数で変数 ip に格納された IPv4 アドレスにに CIDR 部分があるかを調査し、 CIDR 部がない場合は "/32" を付与して出力している。

IPv4 アドレスは "192.0.2.1" の様に「0 から 9 までの数字 1 桁から 3 桁が "." を挟んで 4 組連続する」形式で、 CIDR は "/24" の様に「"/" に続いて 0 から 9 までの数字 1 桁から 2 桁」なので、 正規表現は

[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(\/[0-9]{1,2})?
となるが、 煩雑になるので
([0-9]{1,3}\.){1,3}[0-9]{1,3}(\/[0-9]{1,2})?
とまとめ、 更に数字部分を POSIX クラスに置き換えて
([[:digit:]]{1,3}\.){1,3}[[:digit:]]{1,3}(\/[[:digit:]]{1,2})?
とした。

入力データ中の IPv4 アドレスが重複する可能性がある場合は、直接出力せず一度連想配列に格納する事で uniq(1) 相当の処理も可能となる。

  1awk '{
  2    if(match($0, /([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}(\/[[:digit:]]{1,2})?/))
  3        list[match((ip = substr($0, RSTART, RLENGTH)), /\/[[:digit:]]{1,2}/) ? ip : ip "/32"] = 1;
  4} END {
  5    for(i in liset)
  6        print i;
  7}'
    


Copyright © 2008-2020 Mitzyuki IMAIZUMI. All rights reserved.