I have two arrays:
- first one is ip addresses from billing for blocking
- second is ip addresses from firewall - already blocked
My task is, compare it, and if ip address new in billing list - block it (run a command) if ip address not in billing list unblock it.
Current solutions is:
#billing->router
foreach $ip (@ipfw_ip) {
if ( grep $_ eq $ip, @bill_ip ) {
} else {
`/sbin/ipfw table 11 add $ip`;
print "$ip blocked\n";
}
}
#router->billing
foreach $ip (@bill_ip) {
if ( grep $_ eq $ip, @ipfw_ip ) {
} else {
`/sbin/ipfw table 11 delete $ip`;
print "$ip unblocked\n";
}
}
I hate 'grep' in the loops, and looking for better solution. Any advice?
UPD: difference function from Set::Functional helps me.
for(difference (\@ipfw_ip, \@bill_ip)) {
..._;
}
sub difference(@) {
my $first = shift;
return unless $first && @$first;
my %set;
undef @set{@$first};
do { delete @set{@$_} if @$_ } for @_;
return keys %set;
}
2 Answers 2
You can use Set::Functional
to make the code very short:
use Set::Functional 'difference';
for(difference [@ipfw_ip], [@bill_ip]) {
`/sbin/ipfw table 11 add $ip`;
print "$ip blocked\n";
}
Another advantage of the approach above is that you don't have to worry about duplicate entries in the two arrays.
-
\$\begingroup\$ Thank you alot! I dislike new dependencies but looks into Set::Functional and see the code. Its simple. I will update my question with solution. \$\endgroup\$Korjavin Ivan– Korjavin Ivan2013年06月07日 03:22:34 +00:00Commented Jun 7, 2013 at 3:22
The completely procedural way to write the same is:
foreach my $fw_ip (@ipfw_ip) {
foreach my $bill_ip (@bill_ip) {
if($fw_ip eq $bill_ip) {
...
last;
}
}
}
The main advantage is that it is easy to understand for anybody, and not using too much perl-fu.
I find it odd that you write
if ( grep $_ eq $ip, @bill_ip ) {
} else {
`/sbin/ipfw table 11 add $ip`;
print "$ip blocked\n";
}
In stead of
if ( not grep $_ eq $ip, @bill_ip ) {
`/sbin/ipfw table 11 add $ip`;
print "$ip blocked\n";
}
or even
unless ( grep $_ eq $ip, @bill_ip ) {
`/sbin/ipfw table 11 add $ip`;
print "$ip blocked\n";
}
P.s. always use strict;
and use warnings;
. It looks as if you aren't.
-
\$\begingroup\$ 2xforeach the same then grep in foreach. I hope it possible do that task without loop in loop. And thank you about "if else" no idea how I writed that. Probably there was deleted code. \$\endgroup\$Korjavin Ivan– Korjavin Ivan2013年06月05日 04:12:12 +00:00Commented Jun 5, 2013 at 4:12
-
\$\begingroup\$ Sure - you can do the same completely without a loop. Will be back with that. \$\endgroup\$Michael Zedeler– Michael Zedeler2013年06月05日 06:20:45 +00:00Commented Jun 5, 2013 at 6:20