如何使用Expect.pm(Perl)显示所有输入和输出?

时间:2014-10-06 21:07:46

标签: perl stdout expect

这是一个小的Perl服务器。它显示(1),接受一行输入,然后显示(2)等。如果输入“error”或“commit”,它会给出一个自定义消息。如果键入“exit”,则退出。否则,它只是无休止地接受输入。

use strict;
use warnings;
$|++;

my $counter = 1;
print "($counter) ";

while (<STDIN>) {
  chomp;
  if ($_ eq "error")  {print "Error on command #$counter\n";}
  if ($_ eq "commit") {print "Committing data\n";}
  if ($_ eq "exit")   {print "Exiting program...\n"; exit;}

  $counter++;
  print "($counter) ";
}

现在,这是一个Expect.pm客户端脚本,通过键入各行来与服务器脚本进行交互。

use strict;
use warnings;
use Expect;
$|++;

my $exp = new Expect;
$exp->raw_pty(1);
$exp->log_file("/tmp/expect.out");
$exp->log_stdout(1);

my @commands = (
  "This is the first command",
  "Here is the second command",
  "error",
  "commit",
  "This is the last command",
  "exit",
);


$exp->spawn("./expecttest_server.pl");
foreach my $command (@commands) {
  print "$command\n";
  $exp->send("$command\n");
  $exp->expect(1, '-re','\(\d+\)');
}
$exp->soft_close();

我想要的是能够从头到尾存储整个会话,包括服务器脚本生成的所有内容,以及Expect.pm脚本发送的所有内容。

也就是说,我想要我的客户端脚本能够返回这样的输出,如果你手动运行并与服务器脚本交互,你会看到这样:

(1) This is the first command
(2) Here is the second command
(3) error
Error on command #3
(4) commit
Committing data
(5) This is the last command
(6) exit
Exiting program...

但运行客户端脚本的STDOUT显示如下所示:

This is the first command
(1) (2) Here is the second command
error
(3) Error on command #3
(4) commit
This is the last command
Committing data
(5) (6) exit
Exiting program...

和$ exp-&gt; log_file(tmp / expect.out)指定的文件显示:

(1) (2) (3) Error on command #3
(4) Committing data
(5) (6) Exiting program...

我尝试过记录命令本身的各种组合+ $ exp-&gt; expect()返回的 before_match after_match 变量。但到目前为止,我还没有得到正确的组合。这似乎是一种非常笨重的方式来获得我正在寻找的东西。

那么,捕获整个Expect.pm会话的最佳做法是什么?

感谢任何可以提供帮助的人!

1 个答案:

答案 0 :(得分:0)

在命令行上运行时,服务器会打印

(1)

立即stdout并等待输入。

但是,当您创建Expect对象时,实际上是在设置PTY(伪终端)。您spawn的任何进程都会将其stdin和stdout连接到此PTY,连接到您的shell所连接的TTY。这意味着由Expect对象决定是否显示生成进程的输出;它不会自动显示。

当您spawn进程时,Expect对象保留在输入缓冲区中的任何输出上。当您send进程的字符串时,生成的任何其他输出都将被读入缓冲区。如果PTY启用了回显(默认值),您发送的字符串将被回显,但Expect对象缓冲区的内容不会回显。

当您调用expect方法时,Expect会等到输入缓冲区中出现匹配的字符串。如果在超时到期之前找到匹配项,expect将返回并打印匹配的字符串。

因此,您需要做的只是在 expect第一个命令之前调用send ,如下所示:

服务器

use strict;
use warnings;

$| = 1;

my $counter = 1;
do {
    print "($counter) ";
    $counter++;
} while (<>);

客户端

use strict;
use warnings;

use Expect;

$| = 1;

my $exp = Expect->new;

my $server = './expect_server';
$exp->spawn($server);

my @commands = qw(foo bar baz);

foreach my $command (@commands) {
    $exp->expect(1, '-re', '\(\d+\)');
    $exp->send("$command\r");
}
$exp->soft_close;

输出

(1) foo
(2) bar
(3) baz
(4)

请注意,这与您手动与流程交互时使用的过程完全相同:等待提示,然后键入命令。