0
\$\begingroup\$

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;
}
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\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\$ Commented Jun 7, 2013 at 3:22
1
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\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\$ Commented Jun 5, 2013 at 4:12
  • \$\begingroup\$ Sure - you can do the same completely without a loop. Will be back with that. \$\endgroup\$ Commented Jun 5, 2013 at 6:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.