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

I am attempting to write a script that will gather stats from a 3par storage unit that does not run a unix like operating system. What I am attempting to do is ssh into the device with an ssh key and issue 3par commands to the unit and awk the results. I am trying to take the output and put them into various variables which I will then feed to gmetric to graph in ganglia. The problem is this: the 3par commands are continuous and only stop when you press the 'enter' key. Getting this data into a variable array would be easy but for the fact that the commands are continuous. Here's what I came up with, but this needs to be tweaked to take the above fact into account:
#!/usr/bin/perl use strict; use warnings; #`/bin/echo "SNMP 3PAR DISK STATS start executed on: `date +%D' at '%l +:%M:%S`" >> /var/log/snmp-3par-disk-stats.log` push my @vluns,`ssh -l gmon 3par-S400 statvv -ni | awk '{print $1 }'`; foreach my $vlun (@vluns) { if ($vlun ne "Press") { print "$vlun \n"; } else { last; } } push my @vluns2,`ssh -l gmon 3par-E200 statvv -ni | awk '{print $1 }'` +; foreach my $vlun2 (@vluns2) { if ($vlun2 ne "Press") { print "$vlun2 \n"; } else { last; } }
But it keeps throwing this error:
[gmon@cc126-200 ~]$ ./3par-disk-stats.pl Use of uninitialized value in concatenation (.) or string at ./3par-di +sk-stats.pl line 7.
It seems that it is choking on the $1 that I am passing to awk. I could use some help passing the right variable. Also this is a sample of the text I am trying to parse:
Press 16:34:19 VVname mgmain_data mgnote01_redo1 mgnote01_redo2 mgtool02_data_110G mgtool02_redo1_3G mgtool02_redo2_3G mgnote01_data_85G rcat11_data racprod_redo1a_tpvv racprod_redo1b_tpvv
And this is the output I would like to omit at the end:
---------------------------------------------------------------------- +--------------------- total t 5766 5777 601349 585394 8.4 + 8.6 104.3 101.3 67 Press the enter key to stop...
But most importantly I am looking for a way to exit when it hits the output "press the enter key to stop..." I'd certainly appreciate any guidance the wise monks may have, here. Thanks!

Replies are listed 'Best First'.
Re: 3par data acquistion
by Fletch (Bishop) on Aug 16, 2010 at 21:22 UTC

    Calling awk from Perl is pretty coal-to-Newcastle; just split things yourself. That being said, backquotes (aka qx//; search for "quotelike operators" in perlop interpolate so $1 is expanded into whatever is in $1 before your shell ever sees the command. You'd need to prevent the $ from being seen by perl by using a backslash.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: 3par data acquistion
by BrowserUk (Patriarch) on Aug 16, 2010 at 22:14 UTC
    But most importantly I am looking for a way to exit when it hits the output "press the enter key to stop..."

    Seems likely that the simplest solution might be to just kill the process;

    my $pid = open SSH, '-|', qw[ ssh -l gmon 3par-S400 statvv -ni ] or di +e $!; my @lines; push @lines, $_ while ( $_ = <SSH> ) !~ m[Press the enter key to stop. +..]; kill 9, $pid; ## process data
    Whether it is acceptable to kill an SSH session, and whether that will properly clean up the remote process and session you'll have to look up your docs or try it to find out.

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: 3par data acquistion
by callmeavis (Novice) on Aug 16, 2010 at 21:42 UTC

    Why not use something like IO::Pipe and get rid of awk completely. I suspect that the code below is 'not ideal' for example you very likely don't want/need a sub call to run_command I pass in system, protocol (rsh|ssh) and command in my case so it ate the sub call for some flexibility

    #!/usr/bin/perl use strict; use warnings; use IO::Pipe; my @systems = ('3par-S400','3par-E200'); my $system = undef; my $output = undef; my $command = undef; foreach $system (@systems) { $output = run_command($system); while (<$output>) { next if (m/^$/); last if (m/^Press.*/) #grab bits here instead of using awk } close($output); } sub run_command { my $system = shift; my $protocol = 'ssh'; my $command = "statvv -ni"; my $space = " "; #The following is bad but it works for now.. my $do_command = $protocol . $space . $system . $space . $command; my $cmd = new IO::Pipe; $cmd->reader($do_command); return $cmd; }
      Thanks! This is a very elegant solution and gets me closer to my goal of parsing the output of the 3par commands.

      Just to give you a more complete idea of what I'm dealing with, here is a sample of the output of the statvv -ni commamd :

      $:ssh -l gmon 3par-S400 statvv -ni 11:48:42 08/17/10 r/w I/O per second KBytes per sec Sv +t ms IOSz KB VVname Cur Avg Max Cur Avg Max Cur + Avg Cur Avg Qlen mgmain_data t 412 412 412 17794 17794 17794 5.9 + 5.9 43.2 43.2 3 mgnote01_redo1 t 2 2 2 21 21 21 0.9 + 0.9 9.2 9.2 0 mgnote01_redo2 t 2 2 2 21 21 21 1.4 + 1.4 9.2 9.2 0 mg_date_oraarch t 0 0 0 2 2 2 1.8 + 1.8 4.1 4.1 0 mgtool02_oraarch t 1 1 1 4 4 4 0.3 + 0.3 4.1 4.1 0 mgtool02_data_110G t 238 238 238 1987 1987 1987 20.0 +20.0 8.3 8.3 6 mgtool02_redo1_3G t 9 9 9 40 40 40 0.7 + 0.7 4.6 4.6 0 mgtool02_redo2_3G t 9 9 9 40 40 40 0.3 + 0.3 4.6 4.6 0 mgnote01_data_85G t 3 3 3 45 45 45 4.6 + 4.6 16.4 16.4 0 rcat11_data t 2 2 2 30 30 30 0.2 + 0.2 16.4 16.4 0 racprod_redo1a_tpvv t 189 189 189 33379 33379 33379 11.8 +11.8 176.4 176.4 6
      Ideally what I would like to do is grab each discrete piece of info and stock that in it's own variable so that I can graph trends in each one. As much as I love perl, I'm a little too novice to do this just yet, tho I strive to be able to do things like this!

      As it stands now there is no output from the script. If I take the $output variable and print it, this is what I see:

      [gmon@cc126-200:~] $:./3par-disk-stats.pl IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::En +d=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0 +e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::P +ipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GL +OB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e941 +0)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe: +:End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0 +xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO +::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End +=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e +9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pi +pe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLO +B(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410 +)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe:: +End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0x +e0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO: +:Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End= +GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9 +410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pip +e::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB +(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410) +IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::E +nd=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe +0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO:: +Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=G +LOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e94 +10)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe +::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB( +0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)I +O::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::En +d=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0 +e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::P +ipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GL +OB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e941 +0)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe: +:End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0 +xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO +::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End +=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e +9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pi +pe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLO +B(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410 +)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe:: +End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0x +e0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO: +:Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End= +GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9 +410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pip +e::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB +(0xe0e9410)IO::Pipe::End=GLOB(0xe0e9410)IO::Pipe::End=GLOB(0xe1c9ca0) +IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::E +nd=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe +1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO:: +Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=G +LOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9c +a0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe +::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB( +0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)I +O::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::En +d=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1 +c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0)IO::Pipe::End=GLOB(0xe1c9ca0]
      So I'm really unsure at this point how I can get at the data that I want. But it looks like you've dealt well with the end of the output with this chunk of code!
      while (<$output>) { next if (m/^$/); last if (m/^Press.*/) #grab bits here instead of using awk }
      Without access to awk, however, I am really unsure as to how I can grab the data I want and throw that into some variables I can use. Thanks

        Use the "$_" scalar to work with individual lines inside the while loop. You can do something like this until you get comfortable with "$_"

        next if (m/^$/); last if (m/^Press.*/) my $line = $_; #grab bits here instead of using awk
        I'd also suggest looking at split to put the data into variables:
        ($rw,$io_s_cur,$io_s_avg,$io_s_max,$kb_s_cur,$kb_s_avg,$kb_s_max,$svt_ +ms_cur,$svt_ms_avg,$iosz_cur,$iosz_avg,$qlen) = split(/\s+/, $line, 1 +3);

        The last bit is the first 3 lines in this output; unless you need them for something I'd use the "last if" in the first code block above as a starting point; change last to next and modify the match m//

Re: 3par data acquistion
by Monkeh (Initiate) on Aug 18, 2010 at 05:18 UTC

    > The problem is this: the 3par commands are continuous and only stop when you press the 'enter' key.

    Most if not all of the stat commands have the "-iter <x>" option, which limits the output to <x> iterations. You can combine that with the "-d <y>" option to average the output over <y> seconds.

    So you could change your command to be...

    "ssh -l gmon 3par-S400 statvv -ni -d 30 -iter 1"

    and just call that each time you want an additional set of stats.

    BTW, depending upon the info you're trying to graph, statvlun, or "statvlun -vvsum" might be more appropriate output.