Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

perl expect script to login to multiple machines

3,347 views
Skip to first unread message

Perl_haxor 123

unread,
Jan 3, 2010, 4:56:24 PM1/3/10
to Perl Beginners
Hi All,

I'm new to perl and facing a problem........ I'm using a perl
expect script to login to multiple machines (having same username and
password) and execute the date command, initially i tested on one machine,
it worked fine...........but when i use a foreach loop to test the same
thing on two machines (the code is shown below), it didn't work.......it
just worked on the first machine (10.10.10.1) ........can someone please
help me out with this problem?......how can i use the perl expect script to
login to the multiple machines (assuming they have same username and
password) and execute commands?.. Kindly help me with this problem

#############################################################
#!/usr/bin/perl -w
use strict;
use Expect;


foreach ("10.10.10.1", "10.10.10.2") {
print "Spawning to the $_\n";
$exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";

#This part checks for the password prompt, if it doesn't get the password
prompt the errors are displayed.
unless($exp->expect(10, '-re','.*password:\s*')){

if( $exp->before()) {
print $exp->before();
print "\n";
}
else {

print "Timed out\n";
}
next;
}


print "Sending password to the host\n";

$exp->send("password\r");
print "\n";


#This code will handle any errors after the password is sent

unless($exp->expect(10, '-re', '.*[#$>]')) {

if($exp->before() =~ /(Permission.*\s*.*)/) {
print "\n";
print "Invalid password\n";
}
else {

print "timed out\n";

}
exit;

}


print "sending date command\n";

$exp->send("date\r");
$exp->expect(15, '-re', '.*[#$>]' );
$exp->soft_close();

}
#############################################################

Alvaro Mantilla Gimenez

unread,
Jan 3, 2010, 6:15:45 PM1/3/10
to perl_haxor 123, Perl Beginners
Hello,

I know this is a Perl question but is not more easier to log in with
ssh public key method and execute the commands inside the foreach and
don't do all the username/password code?

Regards,

Alvaro

Alvaro Mantilla Gimenez

unread,
Jan 3, 2010, 10:47:10 PM1/3/10
to Jeremiah Foster, perl_haxor 123, Perl Beginners
On Mon, 2010-01-04 at 02:38 +0100, Jeremiah Foster wrote:

> On Jan 4, 2010, at 24:15, Alvaro Mantilla Gimenez wrote:
>
> > Hello,
> >
> > I know this is a Perl question but is not more easier to log in with
> > ssh public key method and execute the commands inside the foreach and
> > don't do all the username/password code?
>
> Sometimes - like when you have a cluster of machines - it is easier and faster to write a command once and have it execute on all the machines. Expect is really good for this since you can just feed it a list of machines and commands and expect just goes and does its thing.

Sorry...probably my bad English wasn't clear enough:

1.- You need one valid ssh account on each server (even if it is a
cluster of servers).
2.- SSH let's you execute remote commands on that servers.
3.- The perl script executes commands on that servers
4.- Expect do his part of the job with the outputs of the commands
executed.

So, you can share your public ssh key in each target server to log in
directly with the valid ssh account without a password (and save
yourself about the first part of the perl/expect code about the
authentication part using a much easier method to log in) and get a
valid procedure to execute the commands.

I agree with you that it is much easier to define the list of servers
with a var or maybe open a file...or whaterever...with that information.
Then the "foreach" just need to read that and execute the commands but
free of the too much code doing the authentication and validation
responses about the username/password.

Don't you think?

Regards,

Alvaro

> >>
> >> foreach ("10.10.10.1", "10.10.10.2") {
> >> print "Spawning to the $_\n";
> >> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
>

> Don't you think it is much clearer to add a name to the default var? Like this:
>
> my @servers = qw/ 10.10.10.1 10.10.10.2 /;
> foreach my $server (@servers)
> print "Spawning to $server\n";


> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
>
> >>
> >>
> >> #This part checks for the password prompt, if it doesn't get the password
> >> prompt the errors are displayed.
> >> unless($exp->expect(10, '-re','.*password:\s*')){
>

> I haven't tested all your code, but expect is notoriously difficult to use. Matching the prompt and such exactly is a pain. Expect itself offers a little bit easier debugging output sometimes too.
>
> Jeremiah

C.DeRykus

unread,
Jan 4, 2010, 8:47:37 AM1/4/10
to begi...@perl.org
On Jan 3, 1:56 pm, perl.ha...@gmail.com (Perl_haxor 123) wrote:
> Hi All,
>
>            I'm new to perl and facing a problem........ I'm using a perl
> expect script to login to multiple machines (having same username and
> password) and execute the date command, initially i tested on one machine,
> it worked fine...........but when i use a foreach loop to test the same
> thing on two machines (the code is shown below), it didn't work.......it
> just worked on the first machine (10.10.10.1) ........can someone please
> help me out with this problem?......how can i use the perl expect script to
> login to the multiple machines (assuming they have same username and
> password) and execute commands?.. Kindly help me with this problem
>
> #############################################################
> #!/usr/bin/perl -w
> use strict;
> use Expect;
>
> foreach ("10.10.10.1", "10.10.10.2") {
> print "Spawning to the $_\n";
> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
>

No idea really but you might want to invoke ssh with debug settings
for possible additional clues:

spawn("ssh -v -l username .... ") ... # man ssh

--
Charles DeRykus

Salvador Fandino

unread,
Jan 5, 2010, 10:00:11 AM1/5/10
to perl_haxor 123, Perl Beginners
perl_haxor 123 wrote:
> Hi All,
>
> I'm new to perl and facing a problem........ I'm using a perl
> expect script to login to multiple machines (having same username and
> password) and execute the date command, initially i tested on one machine,
> it worked fine...........but when i use a foreach loop to test the same
> thing on two machines (the code is shown below), it didn't work.......it
> just worked on the first machine (10.10.10.1) ........can someone please
> help me out with this problem?......how can i use the perl expect script to
> login to the multiple machines (assuming they have same username and
> password) and execute commands?.. Kindly help me with this problem

There are several CPAN modules (Net::OpenSSH, Net::SSH2, Net::SSH::Perl,
Net::SSH::Expect) that allow to run commands in remote machines through
SSH. Any one of them will release you of the burden of handling
authentication and capturing the output of the remote command.


For instance:

use Net::OpenSSH;

for my $host (@hosts) {
my $ssh = Net::OpenSSH->new($host, user => $user, passwd => $passwd);
if ($ssh->error) {
warn "unable to connect to $host: ". $ssh->error;
next;
}
my $date = $ssh->capture('date');
print "$host: $date";
}

- Salva

Jeremiah Foster

unread,
Jan 3, 2010, 8:38:54 PM1/3/10
to Alvaro Mantilla Gimenez, perl_haxor 123, Perl Beginners

On Jan 4, 2010, at 24:15, Alvaro Mantilla Gimenez wrote:

> Hello,
>
> I know this is a Perl question but is not more easier to log in with
> ssh public key method and execute the commands inside the foreach and
> don't do all the username/password code?

Sometimes - like when you have a cluster of machines - it is easier and faster to write a command once and have it execute on all the machines. Expect is really good for this since you can just feed it a list of machines and commands and expect just goes and does its thing.
>>

>> foreach ("10.10.10.1", "10.10.10.2") {
>> print "Spawning to the $_\n";
>> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";

Don't you think it is much clearer to add a name to the default var? Like this:

my @servers = qw/ 10.10.10.1 10.10.10.2 /;
foreach my $server (@servers)

print "Spawning to $server\n";


$exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";

>>
>>
>> #This part checks for the password prompt, if it doesn't get the password
>> prompt the errors are displayed.
>> unless($exp->expect(10, '-re','.*password:\s*')){

I haven't tested all your code, but expect is notoriously difficult to use. Matching the prompt and such exactly is a pain. Expect itself offers a little bit easier debugging output sometimes too.

Jeremiah

perl_haxor 123

unread,
Jan 5, 2010, 5:33:34 PM1/5/10
to Salvador Fandino, Perl Beginners
Hi all,

I got the solution for this problem..........the reason is that
the new expect object had to be created for each machine that is

$exp = new Expect has to be inside the foreach loop, in my earlier code it
was outside the foreach loop.....Thanks you all for the solutions......i
tried using Net::SSH2 and Net::SSH::Perl and it didn't work for me so i had
to use expect.

Thanks

0 new messages