2

我有一些代码正在运行。由于复杂性和长度,我想也许可以使用一些代码来让我的生活变得轻松。所以代码正在使用>commandA

output
results
are
popping
...
here

我想计算(正在运行)banana的输出中出现的次数commandA,当计数为 10 时,我想停止处理(使用CTRL+ Z)和

echo "************we reached 10**********************"

并重新开始。

我在 unix 系统上用 perl 编写代码。

编辑:我不能在这里使用 grep 函数,因为命令已经运行。或者将运行但没有 grep 函数。在命令运行之前,我将打开我的程序以在终端输出中查找特定的单词。现在使用 grep 会很容易,但我不知道 perl 中的哪个函数实际上将输出作为标准输入输入到终端

4

1 回答 1

1

您可以通过从另一个程序open到您的 Perl 程序的管道来启动另一个程序,然后逐行读取它的输出,直到达到终止条件:

open my $pipe, 'commandA |'
    or die "Error opening pipe from commandA: $!\n";

my $n = 0;
while (<$pipe>) {
    $n++ if /banana/;
    last if $n >= 10;
}
close $pipe;  # kills the command with SIGPIPE if it's not done yet

print "commandA printed 'banana' ", ($n >= 10 ? "at least 10" : $n), " times.\n";

不过,这里有几个陷阱需要注意。一个是关闭管道只会在下一次尝试打印某些内容时杀死另一个程序。如果其他程序可能运行很长时间而不产生任何输出,您可能需要kill明确地执行它。

为此,您需要知道它的进程 ID,但方便的是,这正是open您打开管道时返回的内容。但是,您可能希望使用 的多参数版本open,以便返回的 PID 将是实际 commandA 进程的 PID,而不是用于启动它的 shell:

my $pid = open my $pipe, '-|', 'commandA', @args
    or die "Error opening pipe from commandA: $!\n";

# ...
kill 'INT', $pid;  # make sure the process dies
close $pipe;

另一个陷阱是输出缓冲。大多数程序实际上并不直接将它们的输出发送到输出流,而是将其缓冲直到积累足够多或直到缓冲区被显式刷新。您通常不会注意到这一点的原因是,默认情况下,如果许多程序(包括 Perl)\n检测输出流转到交互式终端(即 tty)。

但是,当您将一个程序的输出通过管道传输到另一个程序时,第一个程序使用的 I/O 库可能会注意到输出进入管道而不是 tty,并且可能会启用更积极的输出缓冲。通常这不会成为问题,但在某些有问题的情况下,它可能会在其他程序打印字符串的时间与您的程序接收它的时间之间增加相当大的延迟。

不幸的是,如果您无法修改其他程序,那么您将无法轻松做到这一点。可以用一种叫做“pseudo-tty”的东西来替换管道,它看起来像另一个命令的交互式终端,但这有点复杂。不过,有一个 CPAN 模块可以稍微简化它,称为IO::Pty

(如果你可以修改其他程序,那就容易多了。例如,如果它是另一个 Perl 脚本,你可以$| = 1;在脚本的开头添加以启用输出自动刷新。)

于 2013-07-19T12:13:52.967 回答