Forum: Ruby How can I get command's result code, which executing via ssh

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Ivan S. (Guest)
on 2009-06-01 14:09
I use net/ssh library.
My code:
require 'rubygems'
require 'net/ssh'
Net::SSH.start('server', 'login') { |ssh| ssh.open_channel { |ch|
ch.exec('false') { |ch, success| puts success }  } }
"false" is a console program and it always return 1.
Why result of this program is "true"?  What mean "success" here? I think
I misunderstand something.
Robert K. (Guest)
on 2009-06-01 16:20
(Received via mailing list)
On 01.06.2009 12:09, Ivan S. wrote:
> I use net/ssh library.
> My code:
> require 'rubygems'
> require 'net/ssh'
> Net::SSH.start('server', 'login') { |ssh| ssh.open_channel { |ch|
> ch.exec('false') { |ch, success| puts success }  } }
> "false" is a console program and it always return 1.
> Why result of this program is "true"?  What mean "success" here? I think
> I misunderstand something.

This is likely because SSH does not propagate the result of the remote
process.  You can find the details on SSH's manpage.

One way would be to send something like

echo "$?"

as last command and read this.

Kind regards

  robert
Brian C. (Guest)
on 2009-06-01 16:48
Robert K. wrote:
> This is likely because SSH does not propagate the result of the remote
> process.  You can find the details on SSH's manpage.

Ahem??

'man ssh' on my system (Ubuntu Hardy) says:

     ssh exits with the exit status of the remote command or with 255 if
an
     error occurred.

A quick test confirms this to be true. So clearly the exit status *is*
propagated back. More likely it's just a problem with the OP's use of
the Net::SSH API.

Now, the Net::SSH API documentation (*) for exec tells you:

   "success means that the command is being executed, not that it has
completed"

And if it hasn't completed, obviously you can't get the exit status. I
admit the documentation doesn't make it easy to see at a glance how you
*should* get the exit status.

But in any case, I think it's not helpful to post unverified guesses
about the behaviour of such a system.

Regards,

Brian.

(*) http://net-ssh.rubyforge.org/ssh/v2/api/index.html
Brian C. (Guest)
on 2009-06-01 16:59
A quick check of the SSH protocol spec in RFC 4254 says, in section
6.10:

   When the command running at the other end terminates, the following
   message can be sent to return the exit status of the command.
   Returning the status is RECOMMENDED.  No acknowledgement is sent for
   this message.  The channel needs to be closed with
   SSH_MSG_CHANNEL_CLOSE after this message.

   The client MAY ignore these messages.

      byte      SSH_MSG_CHANNEL_REQUEST
      uint32    recipient channel
      string    "exit-status"
      boolean   FALSE
      uint32    exit_status

(and it then goes on to describe the "exit-signal" message as well)

Grepping for exit-status in the net-ssh source turns up an example of
how to get it:

    # * "exit-status" : the exit status of the remote process will be
reported
    #   as a long integer in the data buffer, which you can grab via
    #   data.read_long.
    # * "exit-signal" : if the remote process died as a result of a
signal
    #   being sent to it, the signal will be reported as a string in the
    #   data, via data.read_string. (Not all SSH servers support this
channel
    #   request type.)
    #
    #   channel.on_request "exit-status" do |ch, data|
    #     puts "process terminated with exit status: #{data.read_long}"
    #   end
Brian C. (Guest)
on 2009-06-01 17:09
One other point. It's very dangerous to do

    ch.foo { |ch| ... }

because (in ruby 1.8) 'ch' is bound to the same variable in both cases.
That is, the value assigned to the block parameter also changes the
outer 'ch'. So you should call them something different.

The finished program becomes:

require 'rubygems'
require 'net/ssh'
Net::SSH.start('localhost', 'yourname') { |ssh|
  ssh.open_channel { |chan|
    chan.on_request('exit-status') { |ch, data|
      puts "process terminated with exit status: #{data.read_long}"
    }
    chan.exec('false') { |ch, success| puts success }
  }
}
Aaron T. (Guest)
on 2009-06-01 21:14
(Received via mailing list)
On Mon, Jun 1, 2009 at 3:09 AM, Ivan S. <removed_email_address@domain.invalid> 
wrote:
> I use net/ssh library.
> My code:
> require 'rubygems'
> require 'net/ssh'
> Net::SSH.start('server', 'login') { |ssh| ssh.open_channel { |ch|
> ch.exec('false') { |ch, success| puts success }  } }
> "false" is a console program and it always return 1.
> Why result of this program is "true"?  What mean "success" here? I think
> I misunderstand something.

I just ran into the same problem last week and I ended up doing what
Robert suggested:

retcode = ch.exec('my_command >/dev/null 2>&1 ; echo $?')

you can also do things like is:
results = ch.exec('my_command && echo SUCCESS || echo FAILURE')
Robert K. (Guest)
on 2009-06-02 00:26
(Received via mailing list)
On 01.06.2009 14:48, Brian C. wrote:

> But in any case, I think it's not helpful to post unverified guesses
> about the behaviour of such a system.

I am pretty sure that the ssh on at least one system we have at work
does not return the remote command's exit status.  This is not a guess
but I cannot verify it at the moment now because I do not have access to
the system right now.

  robert
Brian C. (Guest)
on 2009-06-02 00:48
Robert K. wrote:
> On 01.06.2009 14:48, Brian C. wrote:
>
>> But in any case, I think it's not helpful to post unverified guesses
>> about the behaviour of such a system.
>
> I am pretty sure that the ssh on at least one system we have at work
> does not return the remote command's exit status.  This is not a guess
> but I cannot verify it at the moment now because I do not have access to
> the system right now.

You said: "SSH does not propagate the result of the remote process.  You
can find the details on SSH's manpage", but a check of the manpage says
otherwise.

Of course, perhaps older versions of ssh are different. However the
system I checked on was Ubuntu Hardy, which isn't exactly bleeding edge.
Ivan S. (Guest)
on 2009-06-02 00:57
Brian C. wrote:
> One other point. It's very dangerous to do
>
>     ch.foo { |ch| ... }
>
> because (in ruby 1.8) 'ch' is bound to the same variable in both cases.
> That is, the value assigned to the block parameter also changes the
> outer 'ch'. So you should call them something different.
>

We use 1.9

> The finished program becomes:
>
> require 'rubygems'
> require 'net/ssh'
> Net::SSH.start('localhost', 'yourname') { |ssh|
>   ssh.open_channel { |chan|
>     chan.on_request('exit-status') { |ch, data|
>       puts "process terminated with exit status: #{data.read_long}"
>     }
>     chan.exec('false') { |ch, success| puts success }
>   }
> }

Thanks! It's what I need!
This topic is locked and can not be replied to.