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

Monks,

I have this simple piece of code using Net::SSH::Perl to login to a remote host using ssh and return the output of a df -k. This works just fine.
#!/usr/bin/perl use Net::SSH::Perl; use strict; my ($auto_serv, $search_string, $insert_cmd ) = @_; my $cibs_host="www.myhost.com"; my $user = "userid"; my $cnt = 1; my $line; my $ssh = Net::SSH::Perl->new($cibs_host, options => [ "Protocol 2,1", "Debug 2", "identity_files id_dsa"]); $ssh->login($user); my (@out1, $err1, $exit2) = $ssh->cmd("df -k"); foreach $line(@out1) { print "$cnt: $line\n"; $cnt++; }

The problem is the output returned from @out1. Each line of the df -k is not retrieved as a line with a ("\n"). Instead the entire contents of a df -k are contained in one line. I need to be able to parse this output line-for-line. Would anyone know how I can do this? Or rather, what am I doing wrong?

I added the $cnt so I could determine what is being outputed. The entire contents of the df -k end up on 1: or line 1.

Thanks,
Louis

Replies are listed 'Best First'.
Re: Problem with data retrieved from Net::SSH:perl
by xmath (Hermit) on Feb 28, 2003 at 20:13 UTC
    That's correct; the Net::SSH::Perl documentation says the first item of the list returned by $ssh->cmd is the entire output of the command.

    You can use split to split the output into lines:

    my ($out, $err1, $exit2) = $ssh->cmd("df -k"); for my $line (split /\n/, $out) { print "$cnt: $line\n"; $cnt++; }

    If the output is potentially large (this doesn't apply for df -k but might be useful to know in the future), and you want to avoid copying all the data like split does you might do something like:

    my $cnt = 1; while ($out =~ /\G(.+)\n?|\G\n/g) { print "$cnt: $1\n"; $cnt++; }
    or if you're certain the last line ends in a newline, you can simplify the pattern to /\G.*\n/g

    And finally it might be more efficient to use index and substr, but it would certainly yield more complex code.

      If the output is potentially large...
      If the output from (or the input to) the command is large, there is an experimental, undocumented open2 method (which btrott informed me of while I was writing a file transfer script). It returns tied filehandles, so they won't work as arguments for some things which require real filehandles (like old versions of File::Copy or Net::FTP).
      # I may have in and out reversed here, try both ways my ($out, $in)=$ssh->open2("command and args"); close $in; while (<$out>) { # Process output } close $out;
      Thanks xmath. That did it. I had read that $ssh->cmd return the entire output as a first line, but I didn't know how to reverse that.

      Many thanks again.
Re: Problem with data retrieved from Net::SSH:perl
by zengargoyle (Deacon) on Feb 28, 2003 at 20:15 UTC
    my (@out1, $err1, $exit2) = $ssh->cmd("df -k");

    isn't likely to ever work... because you can't have an array as the first thing in a multiple value return. an array in the first slot would suck up all of the values passed back from the subroutine. The Docs say as much. this is what you'll need to do:

    my ($out1, $err1, $exit2 = $ssh->cmd("df -k"); my @out1 = split /\n/, $out1; ...
Re: Problem with data retrieved from Net::SSH:perl
by bugsbunny (Scribe) on Mar 01, 2003 at 21:35 UTC
    as we are on this, can i ask a question..:") I didn't know this module exists and just wanted to do something like this.. What I want to do is to copy a file to remote machine and then restart service.(of cource all this via perl program) The problem is how I can do this when I have forbiden the root login via ssh(want to stay the same).
    The action to be taken (shell way):
    ssh user@remote -c mv /etc/dhcpd.conf /etc/dhcpd.conf.1 scp dhcpd.conf user@remote:/etc/dhcpd.conf ssh user@remote su /etc/init.d/dhcpd restart
    any ideas