当前位置:  开发笔记 > 编程语言 > 正文

如何在Perl中使用timeout-on-read实现'tail -f'?

如何解决《如何在Perl中使用timeout-on-read实现'tail-f'?》经验,为你挑选了1个好方法。

我的问题是如何立即处理输入而不是等待换行的对立面.我想继续阅读不断增长的日志文件,但在文件没有增长指定的秒数后停止.

我在CPAN上找到了Sys :: AlarmCall,并尝试如下所示,但是当我运行时它没有超时:

perl progress.tracker.pl progress.tracker.pl

我猜这与与' <>'运算符相关的自动魔术有关.但我不确定如何重写代码.我没有明确打开一个文件(而不是任意数量的文件),如果没有指定文件则默认为标准输入 - 我只希望将它与一个文件名一起使用.

(该脚本为每行读取生成一个点,每读取50行生成一个换行符,每25行点输出一个时间戳.我用它来跟踪长时间运行的构建的进度.当前的化身是由tail -f,但是这个脚本没有退出,主要是因为它永远不会再获得任何输入来写入现在不存在的进度跟踪器.'last'行东西是我正常处理的日志文件中的标记;我想删除它.超时时间为分钟,而不是亚秒.)

#!/usr/perl/v5.10.0/bin/perl -w
#
# @(#)$Id: progress.tracker.pl,v 1.3 2009/01/09 17:32:45 jleffler Exp jleffler $
#
# Track progress of a log-generating process by printing one dot per line read.

use strict;
use constant DOTS_PER_LINE => 50;
use constant LINES_PER_BREAK => 25;
use constant debug => 0;
use POSIX qw( strftime );
use Sys::AlarmCall;

sub read_line
{
    print "-->> read_line()\n" if debug;
    my $line = ;
    printf "<<-- read_line(): %s", (defined $line) ? $line : "\n" if debug;
    return $line;
}

my $line_no = 0;
my $timeout = 30;
my $line;

$| = 1;     # Unbuffered output

while ($line = alarm_call($timeout, 'read_line', undef))
{
    $line_no++;
    print ".";
    print "\n" if ($line_no % DOTS_PER_LINE == 0);
    printf "%s\n", strftime("%Y-%m-%d %H:%M:%S", localtime(time))
        if ($line_no % (DOTS_PER_LINE * LINES_PER_BREAK) == 0);
    last if $line =~ m/^Trace run finished: /;
}

print "\n";
print $line if defined $line && $line =~ m/^Trace run finished: /;

有什么建议?(最好除了'离开你的****并用C代码'!)


File :: Tail似乎很好地满足了我的要求.修订后的代码是:

#!/usr/perl/v5.10.0/bin/perl -w
#
# @(#)$Id: progress.tracker.pl,v 3.2 2009/01/14 07:17:04 jleffler Exp $
#
# Track progress of a log-generating process by printing one dot per line read.

use strict;
use POSIX qw( strftime );
use File::Tail;

use constant DOTS_PER_LINE   => 50;
use constant LINES_PER_BREAK => 25;
use constant MAX_TIMEOUTS    => 10;
use constant TIMEOUT_LENGTH  => 30; # Seconds

my $timeout    = TIMEOUT_LENGTH;
my $line_no    = 0;
my $n_timeouts = 0;
my $line;

sub print_item
{
    my($item) = @_;
    $line_no++;
    print "$item";
    print "\n" if ($line_no % DOTS_PER_LINE == 0);
    printf "%s\n", strftime("%Y-%m-%d %H:%M:%S", localtime(time))
        if ($line_no % (DOTS_PER_LINE * LINES_PER_BREAK) == 0);
}

$| = 1;     # Unbuffered output

# The foreach and while loops are cribbed from File::Tail POD.
my @files;
foreach my $file (@ARGV)
{
    push(@files, File::Tail->new(name=>"$file", tail => -1, interval => 2));
}

while (1)
{
    my ($nfound, $timeleft, @pending) = File::Tail::select(undef, undef, undef, $timeout, @files);
    unless ($nfound)
    {
        # timeout - do something else here, if you need to
        last if ++$n_timeouts > MAX_TIMEOUTS;
        print_item "@";
    }
    else
    {
        $n_timeouts = 0;  # New data arriving - reset timeouts
        foreach my $tail (@pending)
        {
            # Read one line of the file
            $line = $tail->read;
            print_item ".";
        }
    }
}

print "\n";
print $line if defined $line && $line =~ m/^Trace run finished: /;

还有改进的余地; 特别是,超时应该是可配置的.但是,它似乎按我的意愿工作.需要更多的实验和调整.

似乎$ tail-> read()函数一次读取一行; POD并不完全明显.


遗憾的是,经过进一步的实际使用,似乎我使用File :: Tail代码的方式不能满足我的需要.特别是,一旦它停在一个文件上,它似乎不会再次恢复.我没有花时间试图找出问题所在,而是重新选择了替代方案 - 我自己在C中编写代码.花了不到2个小时的时间来获得一个我想要添加的铃声和口哨的版本.我不确定我是否能够快速地将这些内容导入Perl,除了(我使用的)File :: Tail的调试之外.一个奇怪的是:我设置我的代码使用4096字节缓冲区; 我发现构建过程中的一行我监视的长度超过5000字节.好吧 - 代码仍然使用4096字节的缓冲区,但是为这样的超长线发出一个点.足够我的目的.



1> Dave Sherohm..:

您是否尝试过File :: Tail来处理实际拖尾而不是强迫来完成这项工作?

或者,如果那件作品确实有效,那么失败的方式是什么?

推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有