http://www.perlmonks.org?node_id=784722

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

<< UPDATED WITH SIMPLER TEST CASE - SAME BEHAVIOUR >> I have an reasonably complex Perl program which is using Perl Expect - part of it is sending initialization information to a modem bank and its doing this sending information slowly using send_slow. The thing is its expecting on it before its finished sending what is there and i cannot work out whats causing it to stop sending. It should be sending AT &F X3 S38=0 \N2 but it always jumps out when it gets to the = sign The part of the program that sends it looks like this
#!/usr/bin/perl -w use strict; use Expect; use Data::Dumper; my $timeout = '20'; my $user_ts = '192.10.1.1 8000'; my $user_ts_user = 'username'; my $user_ts_pass = 'password'; my $exp; $exp = Expect->spawn("telnet $user_ts") or die "Cannot spawn teln +et: $!\n"; my $spawn_ok; $exp->raw_pty(0); $exp->exp_internal(0); $exp->slave->stty(qw(-a)); #$exp->slave->stty(qw(raw -echo)); #$exp->slave->clone_winsize_from(\*STDIN); do_exp ($timeout, 'login', "$user_ts_user\r",0); do_exp ($timeout, "password:", "$user_ts_pass\r",0); do_exp ($timeout, 'Connected to line', "AT &F X3 S38=0 \\N2\r",1) +; $exp->interact(); sub do_exp { my ($_timeout, $_lookfor, $_send,$_slow) = @_; if (my $out = $exp->expect($_timeout,'-re',$_lookfor +)) { print "out=".$out."\n"; if ($_slow == 0){ $exp->send("$_send"); } else { print "Send_SLOW\n"; my @SlowChars = split(//,$_send); print Dumper(@SlowChars); my $return = $exp->send_slow(1,@SlowChars); print Dumper($return); } } else { print Dumper($exp); die "Timeout waiting for $_lookfor.\n"; } }
The logfile output looks like:-
spawn id(4): Does `: *********\n\r\n\r0460127 Connected to line MODEM: +4O at 115200 8N1\n\r\n\r' match: pattern #1: -re `Connected to line'? YES!! Before match string: `: *********\n\r\n\r0460127 ' Match string: `Connected to line' After match string: ` MODEM:4O at 115200 8N1\n\r\n\r' Matchlist: () Printed character 'A' to spawn id(4). Printed character 'T' to spawn id(4). AReceived 'T' from spawn id(4) Printed character ' ' to spawn id(4). TReceived ' ' from spawn id(4) Printed character '&' to spawn id(4). Received '&' from spawn id(4) Printed character 'F' to spawn id(4). &Received 'F' from spawn id(4) Printed character ' ' to spawn id(4). FReceived ' ' from spawn id(4) Printed character 'X' to spawn id(4). Received 'X' from spawn id(4) Printed character '3' to spawn id(4). XReceived '3' from spawn id(4) Printed character ' ' to spawn id(4). 3Received ' ' from spawn id(4) Printed character 'S' to spawn id(4). Received 'S' from spawn id(4) Printed character '3' to spawn id(4). SReceived '3' from spawn id(4) Printed character '8' to spawn id(4). 3Received '8' from spawn id(4) Printed character '=' to spawn id(4). 8Received '=' from spawn id(4) Starting EXPECT pattern matching...
I can connect to the modem bank manually and type the whole string in no issue. I'm bemused - any assistance gratefully appreciated Kicks out of the send slow on 0 in S38=0 Simon

Replies are listed 'Best First'.
Re: Perl Expect Send Slow Oddness
by quester (Vicar) on Jul 31, 2009 at 13:43 UTC
    This is partly guesswork since I'm not at my Perl machine to test my theory at the moment, but...

    in the source for Expect, http://cpansearch.perl.org/src/RGIERSIG/Expect-1.21/Expect.pm, the definition of send_slow contains this...
    sub send_slow{ ... while ($chunk = shift) { @linechars = split ('', $chunk); foreach $char (@linechars) { ...
    The while condition really should have been (defined ($chunk = shift)) in order to avoid falling out of the loop when $chunk is false. (In your case it's "0" which is false, but "" would cause the same problem.)

    You could patch your copy of Expect.pm (and optionally submit the patch to the module author for good karma.)

    Oc you could just patch your own code to work around it, which is the path of least resistance. According to the documentation, send_slow pauses after every individual character, not just after each string argument. So you could try changing these lines in your code
    my @SlowChars = split(//,$_send); print Dumper(@SlowChars); my $return = $exp->send_slow(1,@SlowChars);
    to just
    print Dumper($_send); my $return = $exp->send_slow(1,$_send);


    Update: Remembered to add the inner parentheses to (defined ($chunk = shift)).