【问题标题】:How can I show all input and output with Expect.pm (Perl)?如何使用 Expect.pm (Perl) 显示所有输入和输出?
【发布时间】:2014-10-06 21:07:46
【问题描述】:

这是一个小的 Perl 服务器。它显示 (1),接受一行输入,然后显示 (2),等等。如果您键入“错误”或“提交”,它会给出一条自定义消息。如果你输入“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) 这是第一个命令 (2) 这里是第二条命令 (3) 错误 命令 #3 出错 (4) 提交 提交数据 (5) 这是最后一条命令 (6) 退出 退出程序...

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

这是第一个命令 (1) (2) 这里是第二条命令 错误 (3) 命令 #3 出错 (4) 提交 这是最后一条命令 提交数据 (5) (6) 退出 退出程序...

$exp->log_file (tmp/expect.out) 指定的文件显示:

(1) (2) (3) 命令 #3 出错 (4) 提交数据 (5) (6) 退出程序...

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

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

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

【问题讨论】:

  • 为什么在将This is the first command 打印到STDOUT 发送到服务器程序之前会得到(1) This is the first command?你得到的输出正是我所期望的(双关语不是故意的)。
  • @ThisSuitIsBlackNot:如果只是将第一个命令附加到输出变量或文件中,那将很容易。更棘手的问题是,STDOUT 或 $exp->log_file 都不包含格式化的数据,如果您自己与程序交互,它会实际出现。标记为“它应该看起来像这样”的块是我无法弄清楚如何在我的客户端脚本中重建的块。
  • 所以“它应该看起来像这样,”我猜你的意思是,“我希望它看起来像这样。”
  • 为什么不把print "($counter) $_";放在你的服务器上?

标签: perl stdout expect


【解决方案1】:

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

(1)

立即到标准输出并等待输入。

但是,当您创建 Expect 对象时,实际上是在设置 PTY(伪终端)。您spawn 的任何进程都将其标准输入和标准输出连接到此 PTY, 连接到您的外壳连接到的 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)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-14
    • 2012-10-26
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多