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

When I was initially writing, I was able to print from within each subroutine, exactly what I wanted the output to be. However, once I removed the print statements from the subroutines and created the "print" subroutine, my output is not what I intend. The code:
#!/usr/local/bin/perl -w use strict; use File::Find; die "Usage: get-router-info <yyyy/mmdd>\n" unless (@ARGV == 1); ###############VARIABLE DEFS############### my $newdate = $ARGV[0]; my $DATE = $newdate; $DATE =~ s-/--; my $versdir="/a/very/long/path/$newdate/to/version/pop"; my $diag_dir ="/a/very/long/path/$newdate/to/diagbus/pop"; my $rtr_names = "/export/home/limo/Perl/router-list.$DATE"; my $eddie_prv = "/path/to/some/other/file.$DATE"; my $eddie_pub = "/path/to/some/different/file.$DATE"; my $asdir = "/nfs/jumbo/b/Peering/AS123"; my $rtr_diag; my $ver_print_string; my %slots = (); my %version =(); my %rtrs = (); my %peers = (); my @diaglist = (); ########################PROGRAM BEGINS################ #read list of routers for collection into %rtrs &read_rtr_hash; # decide if they are peering, who they peer with. &decide_peer; #get router type and IOS version find(\&version, $versdir); #get module configuration, unless module is procesor, power supply, #clock, or switch find(\&diag, $diag_dir); &print; #########################SUBSROUTINES############################## sub read_rtr_hash { open (RTRLIST, $rtr_names) or die "Cannot open $rtr_names: $!\n"; while (<RTRLIST>) { chomp; my @rtr = split; my $init = "1"; foreach my $device (@rtr) { push @{$rtrs{$device}}, $init; } } } sub decide_peer { open (PRV, "<$eddie_prv") or die "Cannot read $eddie_prv: $!"; while (<PRV>) { chomp; my ($prv, $dev) = (split(' ', lc($_)))[0,3]; if ( exists $rtrs{$dev} ) { if ( exists $peers{$dev}) { $peers{$dev}[0].= "$prv, "; } else { push @{$peers{$dev}}, ("$prv, ", ""); } } } open (PUB, "<$eddie_pub") or die "Cannot read $eddie_pub: $!"; while (<PUB>) { chomp; my ($pub, $dev) = (split(' ', lc($_)))[0,3]; if ( exists $rtrs{$dev} ) { if ( exists $peers{$dev}) { $peers{$dev}[1].= "$pub, "; } else { push @{$peers{$dev}}, ("", "$pub, "); } } } } sub version { @ios_ver = `cat $_ |grep IOS` unless ( $_ =~ m/^\./); my $vers = $_; $vers =~ s/\.bbnplanet\.net//; if (exists $rtrs{$vers}) { foreach my $rtr_name(@ios_ver) { my @tmp_array = split(' ',$rtr_name); if ($rtr_name =~ m/(Version.*?),/) { push @{$version{$vers}}, $rtr_name; $ver_print_string = ("$i[2] $1"); } } } } sub diag { @diaglist = `cat $_ |grep SLOT` unless ($_ =~ m/^\./); my $router = $_; $_ =~ s/\.bbnplanet\.net//; if (exists $rtrs{$router}) { foreach $rtr_diag(@diaglist) { next if ($rtr_diag =~ m/Clock|Switch|Power|Processor/); push @{$slots{$router}}, $rtr_diag; } } } sub print { foreach my $vers_key (sort keys %version) { foreach my $mod_key (sort keys %slots) { my $module = join "", @{$slots{$mod_key}}; foreach my $peer_dev (sort keys %peer) { my ($prv, $pub) = @{$peer{$peer_dev}}; print "$peer_dev:\n"; print "================\n"; print "belongs to AS123\n"; print "private peers: $prv\n"; print "public peers: $pub\n\n"; print "IOS Version: $vers_key\n"; print "$module\n"; } } } } ######################END#######################
The output should be data, retrieved from various files, all data corresponding to each device contained in a pre-specified list of devices. What happens, is that, $peer prints correctly, but the rest of the variables are incorrect, meaning that while they get populated with data, it doesn't correspond to $peer. It corresponds with a different device. Sort of "mismatched". Example:
Router A: =========== belongs to AS123 private peers: 456 #oops, this is data from router b print "public peers: 789 #oops, this is data from router c print "IOS Version: #etc...etc..etc
Can anyone spot anything obviously wrong with my "print" subroutine? Hopefully, this is clear. If more info is needed, please ask.

Replies are listed 'Best First'.
Re: Print Subroutine Problem
by lhoward (Vicar) on Oct 05, 2000 at 05:58 UTC
    The first thing I'd do is change your subroutine's name from print to something that doesn't conflict with the name of the built-in print function.
      I'll do that, but I suspect that that isn't my problem. Thanks for your reply!
Re: Print Subroutine Problem
by acid06 (Friar) on Oct 05, 2000 at 07:22 UTC
    or you could change the print statements inside the print subroutine to CORE::print if you really wanted/needed to keep the name
Re: Print Subroutine Problem
by jreades (Friar) on Oct 05, 2000 at 18:52 UTC

    Although I can't see an obvious error, I'd suggest two points of attack:

    1. Explicitly print to STDOUT or OUTFILE -- in your code it's implicit
    2. Although it *should* work correctly the way you have it set up, it is not exactly great form to not pass variables declared with 'my' to the subroutines that are supposed to manipulate them.

    Here's a stab:

    &print_out(\%version, \%slots, \%peer); sub print_out { my ($vers_key, $mod_key, $peer_dev); my ($version_ref, $slots_ref, $peer_ref) = @_; foreach $vers_key (sort keys %{$version_ref}) { foreach $mod_key (sort keys %{$slots_ref}) { my $module = join "", @{$slots_ref->{$mod_key}}; foreach $peer_dev (sort keys %{peer_ref}) { my ($prv, $pub) = @{$peer_ref->{$peer_dev}}; print STDOUT "$peer_dev:\n"; print STDOUT "================\n"; print STDOUT "belongs to AS123\n"; print STDOUT "private peers: $prv\n"; print STDOUT "public peers: $pub\n\n"; print STDOUT "IOS Version: $vers_key\n"; print STDOUT "$module\n"; } } } }