2

A very simple code to connect to a server, run some commands, disconnect and run some more commands locally.

#!/usr/bin/perl

use strict;
use warnings;

use Expect;

my $timeout = 15;
my $password = "1234";

my $expect = new Expect;
$expect->raw_pty(1);
$expect->spawn("bash\n");

$expect->send("echo run some initial commands locally\n");   # edit: added this line

$expect->send("ssh 1.2.3.4\n");
$expect->expect($timeout,
                [   qr/password/,
                    sub {
                        $expect->send("$password\n");
                    }
                ]
                );
$expect->expect($timeout, [ qr/prompt/ ] );

$expect->send("echo run some commands on the server\n");

$expect->send("exit\n");   # disconnect from the server

$expect->send("echo run some more commands locally\n");

$expect->send("exit\n");   # exit bash
$expect->soft_close();

This code works right until the first exit command. It disconnects from the server but then the entire script seems to freeze. No other commands are executed and I have to Ctrl+C or wait until it times out.

Edit: It works when I execute commands locally, it works when I execute some remotely, then I want to return to working locally but I can't.

Also, I'd like to do the same with nested ssh's - connect to one server, connect from it to another and so on... and work on all of them.

What am I doing wrong? How can I achieve the desired behaviour?

pynexj
  • 19,215
  • 5
  • 38
  • 56
NPS
  • 6,003
  • 11
  • 53
  • 90
  • 1
    It looks like you're trying to send a command to the server after disconnecting. I wouldn't expect that to do much. – Degustaf May 07 '15 at 14:44
  • As for why it hangs, it could be an issue with how the timeout is implemented. What OS are you running? – Degustaf May 07 '15 at 14:45
  • 2
    My first question is why use the Expect module to run local commands? Wouldn't using `system` or `IPC::Run` or `IPC::Open2` be easier? And for the ssh commands, I'd use one of the SSH modules instead of Expect. – Ron Bergin May 07 '15 at 14:58
  • @Degustaf RonBergin I've edited my post and added some more code and description of what my approach is and what I want to achieve. I don't want to send a command to the server after disconnecting - I want to send them to my local machine and execute there. – NPS May 07 '15 at 16:17
  • 1
    @RonBergin Also, I'll take a look at perl's ssh. I'm new to perl, didn't even realize it had such a module. – NPS May 07 '15 at 16:23
  • 1
    Take a look at the Net::SSH2 module http://search.cpan.org/~rkitover/Net-SSH2-0.53/lib/Net/SSH2.pm – Ron Bergin May 07 '15 at 17:11
  • @RonBergin I checked Net::SSH::Perl and it looks nice but I also want to be able to do other stuff, like telnet. And more importantly, as I wrote in my post, I want to "nest" my ssh's/telnets so I need Expect. – NPS May 08 '15 at 11:08

1 Answers1

2

Apparently right after $expect->send("exit\n"); the script is still trying to send messages to the remote server or to no one (as it's in the process of disconnecting). The solution is to use expect with a prompt text from the local server (but make sure to use pattern that only matches the local prompt and not the remote one!):

$expect->expect($timeout, [ qr/local_prompt/ ] );

or use some kind of delay (send_slow, sleep of some kind, etc...).

NPS
  • 6,003
  • 11
  • 53
  • 90