http://www.perlmonks.org?node_id=1026307

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

Foremost, my profuse apologies to the Perl Monk Community for such a basic, pathetic, high level question. I have been absent from PERL programming for several years, and my attempts at Google searches for a solution have proven fruitless. Here are the basics of what I am attempting to accomplish: 1) Run a command that collects multiple line information (i.e., a flexlm command that lists current users of a certain tool, multiple line output that contains data separated by spaces such as user name, machine, etc.). I have actually accomplished this first task. 2) Collect information from this output and organize it in a usable format. This should be fairly simple. The output from the command has multiples lines. Each line has the same basic format. I want to capture this information in an array where I can identify data from each line that is delimited by spaces, then take parts of this data and apply it to further commands. I have accomplished running the command to collect the data, but have failed to get each line of the data to put applied to an array. Please let me know what further details I can share to give you better insight on answering my question. Thanks, DP

Replies are listed 'Best First'.
Re: Generic Data Collection
by toolic (Bishop) on Mar 30, 2013 at 23:34 UTC
    Please let me know what further details I can share to give you better insight on answering my question.
    Post a small snippet of the output of the command (as few lines as possible). You can also use Super Search to see if anyone has done anything similar.

      Here's a snippet of the code I am working with:

      $flexlm_cmd = "lmutil lmstat -f ${product}"; #other junk $license_cmd = "$flexlm_cmd"; open LICENSES, "$license_cmd |" || die "Can't execute ($license_cmd +) \n$!\n"; while (<LICENSES>) { $data_line = $_; # my @data = split; #print if grep $_ > 99, @data[1..$#data]; if ($data_line =~ /27000 (\d+)/) { @license_pid = $1; } if ($data_line =~ /Total of (\d+) licenses issued/) { $max_licenses = $1; } elsif ($data_line =~ /Total of (\d+) licenses in use/) { $licenses_used = $1; } elsif ($data_line =~ /minutes \(at /) { ($JUNK, $user, $JUNK) = split (/\s+/, $data_line); $user_list ="$user,$user_list"; }

      and here is the line that is giving me trouble. I've tried loading the data into an array (string shown here), but it's not working. I would prefer to put it in an array (more further down)

      elsif ($data_line =~ /\, start /) { $data_line =~ s/^\s+//g; print $data_line; ($user, $IP, $machine, $VER, $JUNK, $PID, $JUNK, $SDAY, $SDATE +, $start_time) = split (/\ /, $data_line); $user_list ="$user,$user_list"; $start_list ="$start_time,$start_list"; $licenses_used++; } } close LICENSES;

      Here's a snippet of the output $flexlm_cmd command output:

      user1 192.168.1.1 machine1 (v1.1) (flexlmserver/27000 1009), start Sat + 3/30 12:53 user2 192.168.1.2 machine2 (v1.1) (flexlmserver/27000 123), start Sat +3/30 2:45

      The code above works fine but not on multiple lines. The variables only end up with the values from the last line (I tried using arrays instead and that didn't work either). My objective is to build arrays where I have paired up the user name (first block of characters in the line), the process ID (the sixth block of characters, and I have to trim the ")"), and the time (the last block of characters). So from the above example, the output of the arrays would be:

      array1 = (user1,1009,12:53) array2 = (user2,123,2:45)

      I need an association between the PID and the time, so I can sort them by time, then perform further processing on the PIDs that are the oldest. That should be easy, but I can't seem to load up the arrays as shown above (if that is indeed the best way to do this). Again, my apologies for the simple question. I am under time pressure to get this done and all the tutorials I have read on arrays, regex and splitting have not all added together for a solution, so I thought I'd seek the wisdom of the monks. Thank you.

        I think your problem is that you're not actually creating an array. Consider:

        use strict; use warnings; my @parsed; # <- Here's the array in question while ( <DATA> ) { my @wanted = ( split )[ 0, 5, 9 ]; $wanted[1] =~ s/\D//g; push @parsed, join ',', @wanted; } print "$_\n" for @parsed; __DATA__ user1 192.168.1.1 machine1 (v1.1) (flexlmserver/27000 1009), start Sat + 3/30 12:53 user2 192.168.1.2 machine2 (v1.1) (flexlmserver/27000 123), start Sat +3/30 2:45

        This gives an output that seems to correspond to what you request (but whether such a datastructure is ideal depends on how you intend to subsequently use it...).

        Just a comment on your code, not exactly related to what you've asked, but here goes anyway, as I was just reading about this last night. You have these two lines.

        ($JUNK, $user, $JUNK) = split (/\s+/, $data_line); ... ($user, $IP, $machine, $VER, $JUNK, $PID, $JUNK, $SDAY, $SDATE, $start +_time) = split (/\ /, $data_line);
        When assigning to a list, you can assign to undef to throw away a value, thereby not creating a useless variable.
        (undef, $user, undef) = split (/\s+/, $data_line); ... ($user, $IP, $machine, $VER, undef, $PID, undef, $SDAY, $SDATE, $start +_time) = split (/\ /, $data_line);
        This is explained in perldata, under 'List value constructors'. It also gets rid of the need to declare $JUNK if you enable strict 'vars', which you probably should consider if you haven't already done so.