Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

redirect stdout into hash

by doctorspears (Novice)
on Jun 13, 2012 at 17:04 UTC ( #976019=perlquestion: print w/ replies, xml ) Need Help??
doctorspears has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, How can I redirect stdout back into a hash in my script (susphash)? Here I am logging into a remote server and running a command. I want all the lines of the command put into a hash. Is there a way to redirect that output that is a bit more elegant than writing to a temporary file and then reading it into a hash?

#!/usr/software/bin/perl -w use strict; use warnings; use Net::SSH2; my $ssh = Net::SSH2->new(); $ssh->debug(0); my $bigcmd = "version"; my %susphash = (); $ssh->connect("11.61.92.10",22); my $pass = 'P@ssw0rd'; $ssh->auth(username => 'root', password =>$pass ); if($ssh->auth_ok()) { runcmd(my_channel($ssh), "$bigcmd"); } sub runcmd { my ($channel, $command) = @_; $channel->exec($command);# or die $@ . $ssh->error(); my $buff; while(!$channel->eof()) { my $buff; $channel->read($buff, 1024); print $buff; } my $rc = $channel->exit_status(); $channel->close(); return $rc; } sub my_channel { my $ssh = shift(@_); my $chan = $ssh->channel('session'); $chan->blocking ( 0 ); $chan->flush(); $chan->ext_data('merge'); return $chan; }

Comment on redirect stdout into hash
Download Code
Re: redirect stdout into hash
by MidLifeXis (Prior) on Jun 13, 2012 at 17:40 UTC

    Where you are reading the data (the while ! eof section is probably where you want to do this. Instead of the print command, you would load it into a buffer for processing it into a hash.

    The way that you are reading the text from $bigcmd will not give you data in any structured form, but just as a string of at most 1024 characters at a time. You will probably want to join the strings together, split them into the actual records (or use regular expressions), and then push them into a data structure.

    One thing that may help get some more help on this is to list a small snippet of what the output looks like, as well as how the resulting output string should look.

    Update: As zentara has also stated, if you are just looking to have a set of lines, and not structured data, reading the data into an array is likely a better option.

    --MidLifeXis

      Thanks folks. The output file looks something like this, only bigger.

      WAFFINITY_NVLOG_COMPLETION = 170613544 0 0 169894032 FREE_CACHE_REFILL = 6071 35904 35904 22483 PURGE_FILE_PURGE = 173463 27149 27149 0 BUF_CACHE_REBALANCE = 27438 4841 4841 0 _WAFL_BACKDOOR = 85407891 10800645 10800645 0 ==================== = ======== ======== ======== ======== Totals = 645100944 11046000 11046000 799567928 msg_cnt (since boot) = 656146947 wafl restart count histogram: (432440632) -- simple counts 0 1 2 3 4 5 6 + 7 429360452 2285980 67923 2963 5226 10431 432485 82 +144 <16 <24 <32 <40 <48 <56 <64 UNUS +ED 135096 22222 9999 4529 2296 1869 1820 + 0 <128 <192 <256 <320 <384 <448 <512 UNUS +ED 7676 2625 1233 718 2225 718 2 + 0 Odd number of elements in hash assignment at ./waflsusp.pl line 36. <1024 <1536 <2048 <2560 <3072 <3584 <4096 UNUS +ED 0 0 0 0 0 0 0 + 0 <8192 <12288 <16384 <20480 <24576 <28672 <32768 UNUS +ED 0 0 0 0 0 0 0 + 0 <65536 <98304 <131072 <163840 <196608 <229376 <262144 >2621 +44 0 0 0 0 0 0 0 + 0 Average: 0.02

      Later I will be pulling various elements out of this data for evaluation. For example, there may be three fields retrieved by name where I need to perform some math on their values.

      Example:

      mycache-hit = 1000

      mycache-miss = 410

      mycache-miss-why = 309

      410/1000 = X, 309/410 = Y, etc etc

Re: redirect stdout into hash
by zentara (Archbishop) on Jun 13, 2012 at 17:40 UTC
    Why do you need a hash? An array might be simpler. With a hash, you will need to increment a hash key counter, whearas with an array, you just keep pushing each recv into the array in order received. Anyways, for a hash, something like this would work. There is one glitch, since you are reading a $buf of size 1024, you have no idea where the newlines are going to be, so each hash entry may be an incomplete line, which is continued in the next hash entry. It may be better to concantate all received $buf into one long string, then split the string on newlines at put those lines into a hash.
    use warnings; use Net::SSH2; use Data::Dumper; my $ssh = Net::SSH2->new(); # make a global hash for storage my %hash; # make a global counter for incrementing the hash keys my $counter = 0; ...... ...... if($ssh->auth_ok()) { runcmd(my_channel($ssh), "$bigcmd"); } # read output ( but lines may be split ) print $DATA::Dumper( \%hash ),"\n"; __END__ sub runcmd { my ($channel, $command) = @_; $channel->exec($command);# or die $@ . $ssh->error(); my $buff; while(!$channel->eof()) { my $buff; $channel->read($buff, 1024); # print $buff; $hash{$counter} = $buf; $counter++; } my $rc = $channel->exit_status(); $channel->close(); return $rc; }

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      Its seems everyone is right that an array may be easier. For memory efficiency, what is the best way to pipe the output into an array?
        If you want to change from hash, a concated scalar string is probably your best bet, unless you need an array of lines.Here is how to do either way.
        # make a global array for storage my @array; #or make a global scalar string my $storage_string; ..... ..... while(!$channel->eof()) { my $buff; $channel->read($buff, 1024); # print $buff; push @array, $buf; # pushes $buf into next array slot # or use a concated string $storage_string .= $buf; # concantates $buf onto end of stri +ng }
        When you want to read the array, you have a couple of options. Since your newlines may still be out of place, you may get staggered lines, but if you print the array it may reassemble itself properly
        $/ = ''; # change output separator to nothing instead of newline print @array, "\n";
        but this just recreates a string with embedded newlines

        If you go with the concated string route, you can easily split on newlines:

        my @lines=split( /\n/, $storage_string); print "@lines\n"; # or since $storage_string contains embedded newlines, just printing i +t would work print "$storage_string\n";
        Either way, an array joined with the output separator set to '', or a concated string split on newlines should give good results.

        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku ................... flash japh
Re: redirect stdout into hash
by aaron_baugher (Deacon) on Jun 13, 2012 at 18:51 UTC

    Since the Net::SSH::Channel object is also a tied filehandle, you can avoid all the C-style read buffering:

    $channel->exec($command); my @array = <$channel>; # read output lines into an array # or my %hash = map { $_ => undef } <$channel>; # read output lines into a +hash's keys

    Aaron B.
    Available for small or large Perl jobs; see my home node.

      Thanks, but the array doesn't seem to be populating when used in the subroutine?

        Show your code. If you instantiate the array with my within the subroutine, it won't be available outside the subroutine, unless you return it.

        Aaron B.
        Available for small or large Perl jobs; see my home node.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://976019]
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (9)
As of 2014-12-19 10:18 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (77 votes), past polls