systemj has asked for the wisdom of the Perl Monks concerning the following question:

I'm fairly new to Perl, and I'm looking for feedback on a script I put together. It works fine, but I hate the way it flows.

The script works like grep, but for subnets specified by ip/mask. The beginning of the script explains it more details (228 lines):

subnet-grep.pl

Thanks

Replies are listed 'Best First'.
Re: Looking for feedback on a (IP address) script
by toolic (Bishop) on Dec 22, 2010 at 22:12 UTC
    Welcome to the Monastery.

    Rather than linking to your code off-site, since it is small enough, you can paste it here inside "readmore" tags. See Writeup Formatting Tips.

    Also, you might get more specific help if you change your node title to mention something about IP addresses. See How do I compose an effective node title?.

    I'm looking for feedback on a script I put together
    There is a tool to help you find coding style issues: perlcritic. Here is some relevant output:
    'Return value of "open" ignored at line 188, column 3. Check the retu +rn value of "open" for success. (Severity: 3)' 'Readline inside "for" loop at line 51, column 16. See page 211 of PB +P. (Severity: 4)' 'Bareword file handle opened at line 120, column 2. See pages 202,204 + of PBP. (Severity: 5)', 'Two-argument "open" used at line 120, column 2. See page 207 of PBP. + (Severity: 5)', 'Two-argument "open" used at line 188, column 3. See page 207 of PBP. + (Severity: 5)'

    I'm not too familiar with IP addresses, but I know there are many CPAN modules which are.

    You can convert your comments to POD and get a manpage for free:

    =head1 Info Script to search text for ip address on a given subnet Subnet can be specified as x.x.x.x/x.x.x.x or x.x.x.x/xx Options are similar to grep: -c count matching lines -v select lines which do not match -f <pattern file> containing one subnet in the form above per lin +e Example: ./subnet-grep.pl 10.5.1.0/24 /etc/hosts Example: ./subnet-grep.pl -c 192.168.1.0/255.255.255.0 input1.txt inp +ut2.txt =cut
    From the command line, use perldoc:
    perldoc subnet-grep.pl

    From the docs for printf:

    Don't fall into the trap of using a "printf" when a simple "print" would do. The "print" is more efficient and less error prone.
      Thanks for the pointers; perlcritic helps considerably.
Re: Looking for feedback on a script
by jwkrahn (Abbot) on Dec 23, 2010 at 01:34 UTC
    die("Usage: $0 [-c] [-v] <-f pattern-file | subnet/netmask> file [file +...]\n") unless ( (defined $#ARGV && $#ARGV > -1) || (defined $opt_f +) ) ; ... if ( defined $#ARGV && $#ARGV > -1) {

    The variable $#ARGV is ALWAYS defined!    You probably want something like this instead:

    die "Usage: $0 [-c] [-v] <-f pattern-file | subnet/netmask> file [file +...]\n" unless @ARGV || defined $opt_f; ... if ( @ARGV ) {


    # remove non-ip-address characters, trim, break into words + to validate $IP_LINE =~ s/[^0-9.]+/ /g ; $IP_LINE =~ s/^ // ; $IP_LINE =~ s/ $// ; my @WORDS = split(/\s+/,$IP_LINE) ;

    Would be better as:

    # remove non-ip-address characters, trim, break into words + to validate $IP_LINE =~ tr/0-9./ /c; my @WORDS = split ' ', $IP_LINE;


    # grep each file for my $FNAME (@ARGV) { if ( ! -r $FNAME ) { printf STDERR "Cannot read: $FNAME\n" ; next ; } open ($INFILE, "<$FNAME") ;

    You have the possibility of a race condition where the file could become non-readable after the -r test.    You should print the error message only if open fails and include the $! variable so you know why it fails.

    # grep each file for my $FNAME (@ARGV) { open my $INFILE, '<', $FNAME or do { warn "Cannot open '$FNAME' because: $!"; next; };
      This is some great advice. Thanks!