perlsshexpect.pm

Perl expect doesn't work after logout


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?


Solution

  • 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...).