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

Dear Monks,
I am a new perl user please be patient.
Here is my problem- Need to check the status for active interfaces on unix boxes(solaris, BSD). I am using the Net:Telnet module and getting the ouput from ifconfig -a command.
I need to parse the output to check the actine interfaces: How should I do it, read the details of the interface in an array and search for status, or any other better way of doing it. Thanks,
Here is text to parse-
------------------------------------------- em0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500 inet netmask 0xffffff80 broadcast ether 00:07:e9:23:5a:cc media: autoselect (10baseT/UTP <half-duplex>) status: active supported media: autoselect 1000baseTX 1000baseTX <full-duplex +> em1: flags=8802<BROADCAST,SIMPLEX,MULTICAST> mtu 1500 ether 00:07:e9:23:5a:cd media: autoselect status: no carrier supported media: autoselect 1000baseTX 1000baseTX <full-duplex +> ti0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 ether 00:60:cf:21:a3:4c media: autoselect (1000baseSX <full-duplex>) status: active supported media: autoselect 1000baseSX <full-duplex> 1000baseS +X ti1: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500 ether 00:60:cf:21:a3:45 media: autoselect (1000baseSX <full-duplex>) status: active supported media: autoselect 1000baseSX <full-duplex> 1000baseS +X

edit (broquaint): added <code> tags

Replies are listed 'Best First'.
Re: Need help to parse the text
by tachyon (Chancellor) on Jun 17, 2004 at 04:29 UTC

    Your first problem is that the format of ifconfig -a may be different on different platforms. For example:

    [root]# uname -s Linux [root]# ifconfig -a eth0 Link encap:Ethernet HWaddr 00:C0:9F:XX:XX:XX inet addr:64.x.x.x Bcast:64.x.x.x Mask: UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:193891504 errors:0 dropped:0 overruns:0 frame:0 TX packets:153456331 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 RX bytes:1718775511 (1639.1 Mb) TX bytes:3265401055 (3114.1 + Mb) Interrupt:16 Base address:0xecc0 Memory:fe100000-fe120000 lo Link encap:Local Loopback inet addr: Mask: UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:56540745 errors:0 dropped:0 overruns:0 frame:0 TX packets:56540745 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:2665326103 (2541.8 Mb) TX bytes:2665326103 (2541.8 + Mb)

    Anyway you need to find a good way to chunkify the data into records. Assuming you get it in a scalar split "\n\n" should probably do the trick. Then the first string in your chunk is the interface name and m/status:\s+(\S+)/ will give your status. That won't work on Linux.

    for my $chunk (split "\n\n", $data) { my ($if) = $chunk =~ m/^(\S+)/; my ($status) = $chunk =~ m/status:\s*(\S+)/; print "$if: $status\n"; }



Re: Need help to parse the text
by NetWallah (Canon) on Jun 17, 2004 at 05:54 UTC
    To get Interface status, I strongly recommend you use SNMP.

    This is a lot more flexible, and powerful, and allows you to monitor externally. Here is some working code:

    use Net::SNMP::Interfaces; my @StatusText = qw(Invalid-0 UP DOWN testing INVALID-4 dormant-5 Not- +Present-6); my $InterfacesObject = Net::SNMP::Interfaces->new(Hostname => $ARGV[0] + || 'localhost', Community => $ARGV[1] || + 'public' ) or die "*ERROR* : Could not connect\n"; my @InterfaceDetails = $InterfacesObject->all_interfaces(); print "Name: " . $_->name() . "\tStatus=" . $StatusText[$_->ifOperStatus()] ." \n" for @InterfaceDetails; ---Run and Output ---- >perl IP-Address-of-target Community-name Name: Serial2/0 Status=UP Name: BRI1/2:2 Status=DOWN Name: BRI1/3 Status=DOWN Name: BRI1/3:1 Status=DOWN Name: BRI1/3:2 Status=DOWN Name: FastEthernet2/0 Status=UP Name: FastEthernet2/1 Status=DOWN Name: Hssi3/0 Status=UP Name: Null0 Status=UP Name: Loopback0 Status=UP Name: Hssi3/0.605 Status=UP Name: BRI1/0 Status=dormant-5 Name: Hssi3/0.700 Status=UP Name: BRI1/0-Physical Status=UP Name: BRI1/0-Signaling Status=dormant-5 Name: BRI1/0:1-Bearer Channel Status=DOWN Name: BRI1/0:2-Bearer Channel Status=DOWN Name: BRI1/1-Physical Status=DOWN Name: BRI1/1-Signaling Status=DOWN Name: BRI1/1:1-Bearer Channel Status=DOWN Name: BRI1/1:2-Bearer Channel Status=DOWN Name: BRI1/2-Physical Status=DOWN Name: BRI1/0:1 Status=dormant-5 Name: BRI1/2-Signaling Status=DOWN Name: BRI1/2:1-Bearer Channel Status=DOWN Name: BRI1/2:2-Bearer Channel Status=DOWN Name: BRI1/3-Physical Status=DOWN Name: BRI1/3-Signaling Status=DOWN Name: BRI1/3:1-Bearer Channel Status=DOWN Name: BRI1/3:2-Bearer Channel Status=DOWN Name: Hssi3/0.100 Status=UP Name: Hssi3/0.679 Status=UP Name: Hssi3/0.686 Status=UP Name: BRI1/0:2 Status=dormant-5 Name: Dialer101 Status=dormant-5 Name: Hssi3/0.576 Status=UP Name: BRI1/1 Status=DOWN Name: BRI1/1:1 Status=DOWN Name: BRI1/1:2 Status=DOWN Name: BRI1/2 Status=DOWN Name: BRI1/2:1 Status=DOWN

    Offense, like beauty, is in the eye of the beholder, and a fantasy.
    By guaranteeing freedom of expression, the First Amendment also guarantees offense.

Re: Need help to parse the text
by bibo (Pilgrim) on Jun 17, 2004 at 04:31 UTC
    Hey GS, try this. It's not fancy, but it does the job...
    #!/usr/bin/perl use strict; my $filename = "ifconfig.txt"; # my @junk; open(JUNK, $filename)|| die "Cannot open file $filename!"; @junk = <JUNK>; close(JUNK); my ($interface, $istatus, $item); foreach $item (@junk) { chop $item; $interface = $item if ($item =~ m/^[A-z][A-z][0-9]:/); $istatus=""; if ($item =~ m/status:/) { my @sjunk = split (/ /, $item); $istatus = $sjunk[$#sjunk]; $istatus = $sjunk[$#sjunk-1] . " " . $sjunk[$#sjunk] if ($istatus + ne "active"); } print "$interface $istatus\n" if ($istatus ne ""); }
Re: Need help to parse the text
by davidj (Priest) on Jun 17, 2004 at 05:20 UTC
    I assume that the format of the ifconfig -a output will always be the same; that is, interface followed by interface information. If that is the case, then the following code sample will work for you. NOTE:
    1) the output of ifconfig -a has been stored in a file
    2) the interface information is stored in a hash where the interface name is the key and its status is the value.

    #!/usr/bin/perl use strict; my ($if, %hash, $key); open(FILE, "<f.txt"); while(<FILE>) { chomp $_; ($if = $_) =~ s/^(\w+?):.+/$1/ if $_ =~ m/^\w+:/; ($hash{$if} = $_) =~ s/.+status:\s+(.+)/$1/ if $_ =~ m/status/; } close(FILE); foreach $key (keys %hash) { print "$key: $hash{$key}\n"; } exit;
    hope this helps,
Re: Need help to parse the text
by eXile (Priest) on Jun 17, 2004 at 05:38 UTC

    Another approach to solve your problem is using the SNMP (Simple Network Management Protocol). If you are allowed to run snmp-daemons on the servers you want to check, its quite easy and you'll get uniform results regardless of the OS (in theory at least). Using tools like 'snmpwalk' you could get the information you want from a remote host like this:

    prompt$ snmpwalk -c mylittlesecret -v 1 remotehost | egrep 'ifDescr|if +AdminStatus' IF-MIB::ifDescr.1 = STRING: sis0 IF-MIB::ifDescr.2 = STRING: vr0 IF-MIB::ifDescr.3 = STRING: lo0 IF-MIB::ifDescr.4 = STRING: faith0 IF-MIB::ifAdminStatus.1 = INTEGER: up(1) IF-MIB::ifAdminStatus.2 = INTEGER: up(1) IF-MIB::ifAdminStatus.3 = INTEGER: up(1) IF-MIB::ifAdminStatus.4 = INTEGER: down(2)
    Just be sure you do this on a well protected intranet (I guess so because you use telnet to connect to the remote host), or use SNMP version 3 which has much better security than the standard version 1 (which I used in the example above, by using '-v 1')

    Of course you could use Net::SNMP instead of 'snmpwalk' to query remote snmp-daemons.

Re: Need help to parse the text
by jZed (Prior) on Jun 17, 2004 at 14:16 UTC
    Net::Ifconfig::Wrapper provides everything you need to get ifconfig -a info from within perl, including preparsing the data while accounting for platform differences.