IPアドレス、MACアドレスをインクリメントしたい、というへんな依頼を受けたのでスクリプト書いてみた。
どっちも基本方針はこう。
- いったん数値に変換
- インクリメント
- 文字列に戻す
そしてモジュールなにも使わない。
IPアドレス
「ちゃんとしたIPアドレスかどうかを見る必要はない。最後のバイトが0か255にならなければいいよ。」
ということでずいぶん楽になった。入力チェックもなし。
#!/usr/bin/perl use strict; use warnings; my $ip = shift; my $numIncr = shift; my $nIP = ipToNum($ip); for(0..$numIncr-1){ $nIP++ if $nIP % 256 == 255; $nIP++ if $nIP % 256 == 0; print numToIP($nIP++) ."\n"; } sub ipToNum { unpack 'N', pack 'C*', split /\./, shift; } sub numToIP { join '.', unpack 'C*', pack 'N', shift; }
実行
$ perl incr_ip.pl 100.255.255.250 10 100.255.255.250 100.255.255.251 100.255.255.252 100.255.255.253 100.255.255.254 101.0.0.1 101.0.0.2 101.0.0.3 101.0.0.4 101.0.0.5
でけた。
MACアドレス
こっちもちゃんとしたMACアドレスかどうかは気にせず、入力チェックもなし。
#!/usr/bin/perl use strict; use warnings; #no warnings; use bigint; my $mac = shift; my $numIncr = shift; my $nMac = macToNum($mac); print numToMac($nMac++) ."\n" for 0..$numIncr-1; sub macToNum { my $mac = shift; $mac =~ tr/://d; hex $mac; } sub numToMac { my $num = shift; my $mac = sprintf "%04lx%08x", $num>>32, $num & 0xffffffff; join ":", $mac =~ /../g; }
実行
$ perl incr_mac.pl 00:00:00:ff:ff:f9 10 00:00:00:ff:ff:f9 00:00:00:ff:ff:fa 00:00:00:ff:ff:fb 00:00:00:ff:ff:fc 00:00:00:ff:ff:fd 00:00:00:ff:ff:fe 00:00:00:ff:ff:ff 00:00:01:00:00:00 00:00:01:00:00:01 00:00:01:00:00:02
でけた。
・・・といいたいところだけど、00:00:ff:ff:ff:ffより大きなアドレスを扱おうとすると警告がでます。
$ perl incr_mac.pl 0f:ff:ff:ff:ff:f9 10 Integer overflow in hexadecimal number at incr_mac.pl line 18. Hexadecimal number > 0xffffffff non-portable at incr_mac.pl line 18. 0f:ff:ff:ff:ff:f9 0f:ff:ff:ff:ff:fa 0f:ff:ff:ff:ff:fb 0f:ff:ff:ff:ff:fc 0f:ff:ff:ff:ff:fd 0f:ff:ff:ff:ff:fe 0f:ff:ff:ff:ff:ff 10:00:00:00:00:00 10:00:00:00:00:01 10:00:00:00:00:02
このスクリプトならたぶん無視してOK。Perlの数値は内部的にはdoubleで、MACアドレスの48ビットはdoubleの52ビット仮数部に収まるし、演算的には問題はないはず。
(メッセージ自体はuse warningを消すと1つ消えてno warningsで全部消えますが。)
しかし「sprintf "%04lx%08x", $num>>32, $num & 0xffffffff;」は「sprintf "%012lx", $num;」じゃダメなんだなぁ。