Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Expect question

by RaduH (Scribe)
on Oct 26, 2007 at 23:14 UTC ( [id://647520]=perlquestion: print w/replies, xml ) Need Help??

RaduH has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks,
Here's the piece of code I have trouble with:
$sftp = Expect->spawn("sftp $toyName\@$targetServer") || die("Coul +dn't spawn sftp, $!"); $sftp->expect(5, "Password: ") || die("Never got password prompt +on $targetServer, ".$sftp->exp_error()."\n"); print($sftp "$toyPassword\r"); $sftp->expect(5, "sftp\> ") || die("Never got sftp prompt on $targ +etServer, ".$sftp->exp_error()."\n"); print ($sftp "put $backupFileName\r"); $sftp->expect(120, "sftp> ") || die("Never got password prompt on +$targetServer after upload, ".$stfp->exp_error()."\n");
I read the documentation in the Expect module and I saw it can be (well, IS) very strict when it comes to matching the expected strings and the "Password: " string is one particular example being discussed. They warn about the exact number of blank spaces to expect after the colon. I was careful with all of these but I still cannot match the "Password: " prompt (two blanks after : on purpose..)
Here's the resulting output:
Spawned 'sftp user@<host_ip>' spawn id(3) Pid: 23271 Tty: /dev/pts/2 at /usr/lib/perl5/site_perl/5.8.8/Expect.pm line 181 Expect::spawn('Expect', 'sftp user@<host_ip>') called at lifch.p +l line 126 main::upgrade_procedure() called at lifch.pl line 267 expect(Expect=GLOB(0xb96b40) 5 Password: ) called... expect(): handling param 'Password: '... expect(): exact match 'Password: '... Starting EXPECT pattern matching... at /usr/lib/perl5/site_perl/5.8.8/Expect.pm line 561 Expect::expect('Expect=GLOB(0xb96b40)', 5, 'Password: ') called + at lifch.pl line 127 main::upgrade_procedure() called at lifch.pl line 267 spawn id(3): beginning expect. Timeout: 5 seconds. Current time: Fri Oct 26 17:04:42 2007 spawn id(3): list of patterns: #1: -ex `Password: ' spawn id(3): Does `' match: pattern #1: -ex `Password: '? No. Waiting for new data (5 seconds)... spawn id(3): new data. spawn id(3): read 33 byte(s). spawn id(3): Does `Connecting to <host_ip>...\r\n' match: pattern #1: -ex `Password: '? No. Waiting for new data (5 seconds)... spawn id(3): new data. spawn id(3): read 10 byte(s). spawn id(3): Does `Connecting to <host_ip>...\r\nPassword: ' match: pattern #1: -ex `Password: '? No. Waiting for new data (4 seconds)... TIMEOUT Returning from expect with TIMEOUT or EOF Never got password prompt on <host_ip>, 1:TIMEOUT Closing spawn id(3). at /usr/lib/perl5/site_perl/5.8.8/Expect.pm line 1431 Expect::hard_close('Expect=GLOB(0xb96b40)') called at /usr/lib/p +erl5/site_perl/5.8.8/Expect.pm line 1621 Expect::DESTROY('Expect=GLOB(0xb96b40)') called at lifch.pl line + 0 eval {...} called at lifch.pl line 0 spawn id(3) closed. Pid 23271 of spawn id(3) terminated, Status: 0x100
What am I still doing wrong? Thanks!

Replies are listed 'Best First'.
Re: Expect question
by jasonk (Parson) on Oct 26, 2007 at 23:33 UTC

    You indicate that you put two blanks after the colon on purpose, but then the script times out waiting for the word 'Password' followed by a colon, followed by a single space. So what was the purpose of the second space?


    We're not surrounded, we're in a target-rich environment!
      If you look at the debug dump, two spaces is what's coming back from the SFTP server:
      expect(): handling param 'Password: '... expect(): exact match 'Password: '...
      There are two spaces after : until the end of the quoted string. This is an exact copy/paste from my output. I started with no spaces, then I saw the dump and I added one space, it still didn't and I looked more carefully and noticed there were two spaces, but it still doesn't work.

        I might be wrong of course, but it looks to me like that's just the parsing of the parameter you gave to the function, not what was received from the server.

        Could the problem have something to do with the "exact match" part? You can see it's trying to match against 'Connecting to <host_ip>...\r\nPassword: '

        So perhaps you need something like '.*Password: ' as a pattern? (assuming it takes regexes).

        These two lines of debugging output both display your expect pattern as it is being built by Expect, meaning the text in those two lines is from your code, not from the server.


        We're not surrounded, we're in a target-rich environment!
Re: Expect question
by Argel (Prior) on Oct 27, 2007 at 01:46 UTC
    I don't remember ever having to be that paranoid about spaces, as the (cleaned up and therefore not tested) code below shows.
    print $expect_instance "$username}\r"; ( $which, $why, $match, $before, $after) = $expect_instance->expect( $ +timeout, 'Password:'); if( ! $which ) { myerror( 'send the password:'.$why );
    $before is what came before the match, $match is what it matched on (useful if you passed in more than one match candidate), and $after is what came after the match. Note that $before and $after are strings and they may contain newlines.

    I think you are getting hung up on the spaces when either they do not matter or you could just deal with them later on in your perl code. Though it's been a few years since I touched Expect.pm so maybe it is more rigid than before.

Re: Expect question
by andyford (Curate) on Oct 27, 2007 at 11:21 UTC

    Ignore me if it won't work for you, but something to consider: If you used pre-positioned ssh keys to authenticate instead of passwords, all your problems described here would just go away. Additionally you won't have to retool your Expect machinations when you hit a different server that acts a bit differently. There are many discussions and tutorials on the web, just search for something like 'using ssh key' and you'll retrieve a wealth of information.

    non-Perl: Andy Ford

      Yup, I did think about that and I will use it. However, some scenarios need to go through the more painful experience, cannot always afford the ssh key trick. Thanks for the advice though, good point!
Re: Expect question
by RaduH (Scribe) on Oct 29, 2007 at 15:48 UTC
    OK, I solved the problem. Cannot say I understand why it is the way it is, but it works...

    I was about to try the few lines proposed by Argel when I noticed that example was using single quotes '...'rather than doubles like I was using "..." Before trying those lines I just replaced my doubles with single quotes and changed nothing else. it worked just fine. I even killed the spaces trailing the colon after password and it still matched just fine.

    The string I was trying to match was the "Password:" part of the entire return from the server, which looked like "Connecting to <ip>... \n\rPassword: ". I know using 'Password:' works but I have no idea why. (just went back and read some more about single and double quotes, but I'm still in the fog)

    Since this is a slightly different problem, I just wanted to post here my findings and thank you for your replies. I'll ask the next question in a separate thread.

      I noticed that even in some of my 7 year old code I was normally using single quotes but there are one or two places where I used double quotes. I wonder what platform and what perl you are using? We had a Red Hat 3 (?) system here with perl 5.8.0 on it that had some really odd behavior.

      As a side note, I suspect I was normally using single quotes because that's good practice if the string does not contain anything that needs to be interpolated. Though I suppose actually making them constants would be even better practice but I hate 'use constant'. What I really want is a constant that I can treat like a variable, so if ReadOnly was ever made Core I would likely use that.

      Anyway, thanks for passing the solution on as I'm sure others can benefit and it's always great to hear how things turned out when someone asks a question. Err, well, except for paco, where the mystery is surely better than the answer (unless he has a great hot dog recipe).

        I was running Perl 5.8.8 on a Suse 10.2 machine. ... About that hot dog recipe, if you or anybody else get your hands on it, please post :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://647520]
Approved by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-04-25 05:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found