Will cope with input that includes duplicated, overlapping and adjacent networks. Pipe the input into the script one per line as “x.x.x.x/xx”.
Updated with a fix from andreww that works around a floating point glitch performing log() operations whilst printing the output.
#!/usr/bin/perl -w use strict; my %stage; while (<STDIN>) { chomp; next if ($_ eq ''); (my $ip, my $mask) = $_ =~ /^(\d+\.\d+\.\d+\.\d+)\/(\d+)/; $stage{2**32-(2**(32-$mask))}{unpack('N', pack('C4', split(/\./, $ip)))} = 1; } my %mid; foreach my $mask (sort keys %stage) { ADDR: foreach my $addr (keys %{$stage{$mask}}) { foreach my $seek (sort keys %stage) { last if ($seek == $mask); next ADDR if (defined $stage{$seek}{$addr & $seek}); } $mid{$addr} = $mask; } } my @data; push(@data, { ip => $_, mask => $mid{$_} }) foreach (sort { $a <=> $b } keys %mid); my $c=0; while ($c != @data) { for (my $i=0; $i<$#data; $i++) { next if ($data[$i]->{mask} != $data[$i+1]->{mask}); my $n = $data[$i]->{mask} & $data[$i]->{mask}-1; if (($data[$i]->{ip} & $n) == ($data[$i+1]->{ip} & $n)) { $data[$i]->{mask} = $n; $data[$i+++1]->{ip} = undef; } } $c = @data; @data = grep {defined $_->{ip}} @data; } foreach (@data) { print dec2ip($_->{ip}).'/'.(32-(int(log((2**32)-$_->{mask})/log(2))))."\n"; } sub dec2ip { return join '.' => map { ($_[0] >> 8*(3-$_)) % 256 } 0 .. 3; }