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

My apologies, I'm not a perl programmer (more of a bash scripter by trade), but I've inherited a set of perl scripts that need to be updated for a new OS release and I'm in a bit of trouble trying to fix them. What I'm trying to do is extract a number of relevant network parameters to use in other parts of the script.
#!/usr/bin/perl chomp($syshost = `hostname`); chomp($sysip = `ifconfig | grep -i inet | egrep -v "inet6|127. +0.0.1" | head -n 1 | awk '{print $2}'`); chomp($sysnm = `ifconfig | grep -i inet | egrep -v "inet6|127. +0.0.1" | head -n 1 | awk '{print $4}'`); print "hostname : $syshost\n"; print "IP : $sysip\n"; print "Netmask : $sysnm\n";
What I end up getting however, does not match the expected result.
EXPECTED RESULT hostname : laptop.example.com IP : 10.10.50.21 Netmask : 255.255.255.0 RECEIVED RESULT hostname : laptop.example.com IP : inet 10.10.50.21 netmask 255.255.255.0 destination 1 +0.10.50.1 Netmask : inet 10.10.50.21 netmask 255.255.255.0 destinat +ion 10.10.50.1
If I run the commands in the ` ` sections within my bash shell, I do get the expected result, but with the script, I do not. I've seen some stuff about awk and perl not getting along but it's what I know, and I'm in a bind with inherited code (with 0 comments), a language I am unfamiliar with, and tight deadlines, so any pointers into the right direction would be appreciated.

Replies are listed 'Best First'.
Re: Extracting network information
by 1nickt (Canon) on Sep 01, 2015 at 17:17 UTC

    Hi Kasemodder, welcome to the Monastery.

    First, put use strict; use warnings; at the top of your script and declare your variables with my. It is stupid to try to program Perl without that.

    If you do that you'll get:

    $ perl 1140691.pl Use of uninitialized value $2 in concatenation (.) or string at 114069 +1.pl line 8. Use of uninitialized value $4 in concatenation (.) or string at 114069 +1.pl line 9. hostname : localhost IP : inet 10.5.50.27 netmask 0xffffff00 broadcast 10.5.50.25 +5 Netmask : inet 10.5.50.27 netmask 0xffffff00 broadcast 10.5.50.25 +5
    This tells you that the $2 and $4 are being interpolated by Perl (and they are not initialized in your program). So now you see the problem, thanks to use warnings;. If you escape the dollar signs that you want to use in your awk statement so that they are not interpolated by Perl, you should get what you want.
    #!/usr/bin/perl use strict; use warnings; chomp(my $syshost = `hostname`); chomp(my $sysip = `ifconfig | grep -i inet | egrep -v "inet6|127.0.0.1 +" | head -n 1 | awk '{print \$2}'`); chomp(my $sysnm = `ifconfig | grep -i inet | egrep -v "inet6|127.0.0.1 +" | head -n 1 | awk '{print \$4}'`); print "hostname : $syshost\n"; print "IP : $sysip\n"; print "Netmask : $sysnm\n"; __END__
    Output:
    $ perl 1140691.pl hostname : localhost IP : 10.5.50.27 Netmask : 0xffffff00 $
    There are of course better ways to do this with Perl, without shelling out, but if this does what you want, then 👍

    The way forward always starts with a minimal test.
      Great explanation, it makes a lot more sense now. Didn't know about the use warnings and use strict. I'm sure there's more to it, but this certainly keeps me moving on my way forward.
Re: Extracting network information
by hippo (Archbishop) on Sep 01, 2015 at 17:14 UTC

    Simply escaping the dollars in the awk command will do the trick:

    chomp($sysip = `ifconfig | grep -i inet | egrep -v "inet6|127.0.0.1" | head -n 1 | awk '{print \$2}'`);

    However, I won't be the only one here who recoils at the way this script is constructed. When you have time, it would be a very good idea to rewrite this in a more efficient and robust manner (as an exercise if nothing else).

      Thanks! That did the trick. I'm by no means advocating this as a good way of doing things, but it's a bit of monkey-see monkey-do with the code that was already there (the previous wasn't using awk, but other bash commands), and what I can figure out to do with it. karma++
Re: Extracting network information (with CPAN modules)
by 1nickt (Canon) on Sep 01, 2015 at 17:45 UTC

    Sys::Hostname is in core, the others you'll have to install from CPAN ...

    #!/usr/bin/perl use strict; use warnings; use Sys::Hostname; use Net::Address::IP::Local; use Net::Netmask; my $hostname = hostname; my $ip = Net::Address::IP::Local->public; my $netmask = Net::Netmask->new( $ip )->mask; print "hostname : $hostname\n"; print "IP : $ip\n"; print "Netmask : $netmask\n"; __END__
    Output:
    $ perl 1140691-2.pl hostname : localhost IP : 10.5.50.27 Netmask : 255.255.255.255 $

    Update: if you want the internal IP address you can use gethostbyname() and Socket, which is in Core, and dump Net::Address::IP::Local:

    use Sys::Hostname; use Socket; my $hostname = hostname; my $ip = inet_ntoa( scalar gethostbyname( $hostname ) );
    See perlfaq9.

    The way forward always starts with a minimal test.
Re: Extracting network information
by stevieb (Canon) on Sep 01, 2015 at 17:29 UTC

    I don't have time to try any modules right now (which I'd search out instead of shelling out), but here's a way with less external calls:

    #!/usr/bin/perl use warnings; use strict; my $hostname = `hostname`; my $config = `ifconfig`; $config =~ m/ inet\saddr: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) .*? Mask: (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) /x; if ($1 && $2 && $1 !~ /127\.0\.0/){ my $ip = $1; my $netmask = $2; print "hostname: $hostname" . "IP: $ip\n" . "Netmask: $netmask\n"; } __END__ hostname: steve-ws IP: 10.0.48.1 Netmask: 255.255.255.0