解析输出和计数字符串出现的次数

时间:2013-07-19 06:07:49

标签: linux perl unix

我运行了一些代码。由于复杂性和长度,我认为可能会使用一些代码来让我的生活变得轻松。所以代码使用>commandA

运行
output
results
are
popping
...
here

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

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

然后重新开始。

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

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

1 个答案:

答案 0 :(得分: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时) if < / em>他们检测到输出流进入交互式终端(即tty)。

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

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

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