http://qs321.pair.com?node_id=752906


in reply to Parsing output from a command

Ahh, the power of regular expressions:

use strict; use warnings; my $data; { local $/; $data = <DATA>; } my %drives = (); while ($data =~ /^(\w+)\s*.*?Serial Number\.*(\w*)\s/smg) { $drives{$1} = $2; } while ( my ($key, $value) = each %drives) { print "$key $value\n"; } __DATA__ hdisk0 P1/Z1-Aa 16 Bit LVD SCSI Disk Drive (18200 MB) Manufacturer................IBM Machine Type and Model......ST318305LC FRU Number..................09P4437 Serial Number...............0009E05B Part Number.................09P4436 hdisk1 P1/Z1-Ab 16 Bit LVD SCSI Disk Drive (18200 MB) Manufacturer................IBM Machine Type and Model......ST318305LC FRU Number..................09P4437 Serial Number...............0004A0D2 Part Number.................09P4436

For information on these marvels of modern science, read perlretut. What I've done in the above is:
  1. ^(\w+) - Find a line that starts with alphanumeric characters
  2. \s*.*? - Advance past the smallest amount of arbitrary text until:
  3. Serial Number - I encounter the phrase 'Serial Number'
  4. \.* - Advance past an arbitrary number of '.' characters
  5. (\w*)\s - Find a series of alphanumerics followed by whitespace
The parenthesis capture the results into the variables $1 and $2, which are stored in the hash. The modifiers s and m control how new-lines are treated for matching, and the g modifier makes the while loop repeat so long as a match exists. Also note I localized the default record separator $/, so the entire data section is read in as a single string.

Replies are listed 'Best First'.
Re^2: Parsing output from a command
by Nkuvu (Priest) on Mar 24, 2009 at 16:18 UTC

    Another approach would be to join the lines of the result and match against that. For example:

    #!/usr/bin/perl use strict; use warnings; # Slurp! my @results = <DATA>; my $results_string = join '', @results; # Note: Direct assignment to hash works due # to exactly two matches. Error checking would # not be a bad idea, either (what happens if the # match fails?) my %matches = $results_string =~ /(hdisk\d+).+?Serial Number\.+(\w+)/g +s; for my $device (keys %matches) { print "$device $matches{$device}\n"; } __DATA__ hdisk0 P1/Z1-Aa 16 Bit LVD SCSI Disk Drive (18200 MB) Manufacturer................IBM Machine Type and Model......ST318305LC FRU Number..................09P4437 Serial Number...............0009E05B Part Number.................09P4436 hdisk1 P1/Z1-Ab 16 Bit LVD SCSI Disk Drive (18200 MB) Manufacturer................IBM Machine Type and Model......ST318305LC FRU Number..................09P4437 Serial Number...............0004A0D2 Part Number.................09P4436

    Output:

    hdisk1 0004A0D2 hdisk0 0009E05B