in reply to Changing passwords using Expect.pm through ssh on a large number (75) of systems

I would suggest performing multiple expects, as opposed to doing multi-pattern matching. Consider:
my $exp; foreach (@hosts) { $exp = Expect->spawn("ssh -l $username $_") or die "Cannot spawn ssh: $!\n"; do_exp ($timeout, 'password $', $oldpass); do_exp ($timeout, "$username\]", 'passwd'); do_exp ($timeout, 'password:', $oldpass); do_exp ($timeout, 'password:', $newpass); do_exp ($timeout, 'password:', $newpass); } sub do_exp { my ($_timeout, $_lookfor, $_send) = @_; if ($exp->expect($_timeout, $_lookfor)) { $exp->send($_send); } else { die "Timeout waiting for $_lookfor.\n"; } }
This way your script will look for the patterns in order as opposed to getting confused as to when to send what (especially since three of the patterns you're trying to match are exactly the same). If you want to change the pattern matching from string to regex, you only need to change the following in the do_exp sub:
if ($exp->expect($_timeout, $_lookfor)) {
to:
if ($exp->expect($_timeout,'-re',$_lookfor)) {


One final suggestion: I'd try to match "Old password:" and "New password:" instead of just "password:".

Hope it helps,
scott.

Replies are listed 'Best First'.
Re: Re: Changing passwords using Expect.pm through ssh on a large number (75) of systems
by linebacker (Scribe) on Jul 11, 2002 at 22:25 UTC
    I modified per your recommendation:
    #!/usr/bin/perl -w use strict; use Expect; my $timeout = '5'; my $username = 'luser'; my $newpass = 'luser'; my $oldpass = 'n3wp@ss!'; open(HOSTS,"hosts.txt") or die "Error while opening file:$!\n"; chomp( my @hosts = <HOSTS> ); close(HOSTS) or die "Error while closing file:$!\n"; my $exp; foreach (@hosts) { $exp = Expect->spawn("ssh -l $username $_") or die "Cannot spawn ssh: $!\n";; my $spawn_ok; #$exp->exp_internal(1); do_exp ($timeout, 'password', $oldpass); do_exp ($timeout, "$username\n", "passwd"); do_exp ($timeout, 'password:', $oldpass); do_exp ($timeout, 'password:', $newpass); do_exp ($timeout, 'password:', $newpass); } sub do_exp { my ($_timeout, $_lookfor, $_send) = @_; if ($exp->expect($_timeout,'-re',$_lookfor)) { $exp->send($_send); } else { die "Timeout waiting for $_lookfor.\n"; } }

    but am still having problems.
    I show the output with verbose debugging turned on below:
    Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x835f7e0)', 5, '-re', 'password') cal +led at ./example.pl line 30 main::do_exp(5, 'password', 'n3wp@ss!') called at ./example.pl lin +e 21 spawn id(3): list of patterns: #1: -re `password' spawn id(3): Does `' match: pattern #1: -re `password'? No. luser@10.10.10.39's password: spawn id(3): Does `luser@10.10.10.39\'s password: ' match: pattern #1: -re `password'? YES!! Before match string: `luser@10.10.10.39\'s ' Match string: `password' After match string: `: ' Matchlist: () Sending 'n3wp@ss!' to spawn id(3) Expect::print('Expect=GLOB(0x835f7e0)', 'n3wp@ss!') called at ./ex +ample.pl line 30 main::do_exp(5, 'password', 'n3wp@ss!') called at ./example.pl lin +e 21 Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x835f7e0)', 5, '-re', 'luser^J') call +ed at ./example.pl line 30 main::do_exp(5, 'luser^J', 'passwd') called at ./example.pl line 2 +2 spawn id(3): list of patterns: #1: -re `luser\n' spawn id(3): Does `: ' match: pattern #1: -re `luser\n'? No. n3wp@ss! spawn id(3): Does `: n3wp@ss!' match: pattern #1: -re `luser\n'? No. Timeout waiting for luser

    Without verbose debugging:
    luser@10.10.10.39's password: n3wp@ss!Timeout waiting for luser .
    Thanks again for the assist!
      Sorry, overlooked:
      $exp->send("$_send\n");
      If it's not sent explicitly, Expect doesn't add a return onto the end of the string you're sending. Also, are you sure you want to be matching $username\n? I'm guessing the \n is a typo, somehow...

      I took out the pattern-match statement looking for the ssh password (I'm using keys) and tried the script, and it works for me. Let me know if you're still having trouble...

      scott.
        Thanks,
        $username\n? was a mistake by me

        I just wanted to mention that I had to use
        $exp->send( "$_send\r" );
        for the script to fire properly. I had been reading the perldoc's on the Expect.pm module as well as the 2 pages in the Perl Cookbook. I will add a Net::Ping and Mail::Mailer to the program next (for error checking / availability) as well as reporting. Will post to CUFP when its done. Thanks again sschneid.