<?xml version="1.0" encoding="windows-1252"?>
<node id="861446" title="Getting Call-Response Behavior with Expect" created="2010-09-23 01:40:26" updated="2010-09-23 01:40:26">
<type id="115">
perlquestion</type>
<author id="596967">
gnosti</author>
<data>
<field name="doctext">
I would like to talk to an external program (midish) from
perl using Expect (or Expect::Simple). I want to spawn this program once, keeping the child process loaded while I do other stuff. AFAIK Midish is well-behaved, using STDIN and STDOUT for I/O. However I'm having a hard time getting a reponse reliably after sending a command.
&lt;p&gt;
&lt;b&gt;Update 1: I will investigate approaches other than Expect.&lt;/b&gt;&lt;p&gt;
&lt;p&gt;&lt;b&gt;Update 2: Zentara's solution using IPC::Open3 is *way* simpler.&lt;/b&gt;
&lt;p&gt;
My first experiment was a simple command loop:
&lt;p&gt;
  - get a prompt ("+ready")&lt;p&gt;
  - send a command&lt;p&gt;
  - get a reply&lt;p&gt;

I thought I would try with Expect::Simple, 
however some buffering or command-ordering problems arise.
&lt;p&gt;
&lt;code&gt;
------ test-expect-simple ----

use Modern::Perl;
use Expect::Simple;

$| = 1;
my $obj = Expect::Simple-&gt;new({
	 Cmd =&gt; [ midish =&gt; '-v'],
	 Prompt =&gt; '+ready',
	 DisconnectCmd =&gt; 'exit',
	 Verbose =&gt; 0,
	 Debug =&gt; 0,
	 Timeout =&gt; 100
   });

sub prompt { print "midish&gt; " }


while ( prompt(), my $cmd = &lt;STDIN&gt; ){
	
		exit if $cmd =~ 'quit';
		chomp $cmd;
		$cmd .= "\r";
        $obj-&gt;send( $cmd );
        my @lines = split "\n", $obj-&gt;before;
		splice(@lines, 0, 2); # throw away the first two lines
		say join "\n", @lines;
}

__END__

$perl test-expect-simple
midish&gt; asdf

asdf: no such proc
midish&gt; 1234

midish&gt; ffff

3.5: statement or proc definition expected
midish&gt; ^C

&lt;/code&gt;
&lt;p&gt;
Comment: I'm not getting the full message after
sending a command. Maybe it's a problem with
Expect::Simple.
&lt;p&gt;
So here is the next try, a command loop using Expect.
&lt;p&gt;
&lt;code&gt;
------ test-expect-loop -----

use Expect;
use Modern::Perl;

my $exp = Expect-&gt;spawn("midish","-v")
    or die "Couldn't start program: $!\n";

# don't copy program output to STDOUT
$exp-&gt;log_stdout(0);

$exp-&gt;expect(1, '+ready', \&amp;do_cmd);

sub do_cmd {

	map{say "midish: $_"} split "\n", $exp-&gt;before;
	print "enter command &gt;&gt; ";
	my $cmd = &lt;STDIN&gt;;
	$exp-&gt;send($cmd);
	exp_continue;
}

$exp-&gt;soft_close();

__END__

program output:


$ perl test-expect-loop
enter command &gt;&gt; adsfsd
midish: 
midish: adsfsd
midish: adsfsd: no such proc
enter command &gt;&gt; 1234
midish: 
midish: 1234
midish: 2.5: statement or proc definition expected
enter command &gt;&gt; ffff
midish: 
midish: ffff
midish: ffff: no such proc
enter command &gt;&gt; exit
$ 
&lt;/code&gt;
&lt;p&gt;
Good, I'm getting output after every command.
But my application is structured more like this:
&lt;p&gt;
&lt;code&gt;
call_to_expect($one_command);
execute_other_code();
call_to_expect($another_command);

------ test-expect-unrolled -----

use Expect;
use Modern::Perl;

my $exp = Expect-&gt;spawn("midish","-v")
    or die "Couldn't start program: $!\n";

# don't copy program output to STDOUT
$exp-&gt;log_stdout(0);

$exp-&gt;expect(1, '+ready', \&amp;do_cmd);
print_output();

$exp-&gt;expect(1, '+ready', \&amp;do_cmd);
print_output();

$exp-&gt;expect(1, '+ready', \&amp;do_cmd);
print_output();

sub do_cmd {

	print "enter command &gt;&gt; ";
	my $cmd = &lt;STDIN&gt;;
	$exp-&gt;send($cmd);
}
sub print_output {
	map{say "midish: $_"} split "\n", $exp-&gt;before;
}

$exp-&gt;soft_close();
__END__

program output:

$ perl test-expect-unrolled
enter command &gt;&gt; asdf
enter command &gt;&gt; 1234
midish: 
midish: asdf
midish: asdf: no such proc
enter command &gt;&gt; ffff
midish: 
midish: 1234
midish: 2.5: statement or proc definition expected
&lt;hang&gt; 
^C
$

&lt;/code&gt;
&lt;p&gt;
So, I still have a problem getting a one-to-one
correspondence between the command string and the result
string.
&lt;p&gt;
Any ideas how I could make one call to send a command and get a response, in a way that I can repeat indefinitely?

Thanks for reading!</field>
</data>
</node>
