如何在Perl中使用timeout-on-read实现’tail -f’?
我的问题是
How do I process input immediately instead of waiting for newline的对立面.我想继续阅读不断增长的日志文件,但在文件没有增长指定的秒数后停止.
我在CPAN找到了Sys::AlarmCall,并尝试如下所示,但是当我运行时它没有超时: perl progress.tracker.pl progress.tracker.pl 我猜这与与’<>‘相关的自动魔法有关操作符.但我不确定如何重写代码.我没有明确打开一个文件(而不是任意数量的文件),如果没有指定文件则默认为标准输入 – 我只希望将它与一个文件名一起使用. (该脚本为每行读取生成一个点,每读取50行生成一个换行符,每25行输出一个时间戳.我用它来跟踪长时间运行的构建的进度.当前的化身由尾部提供 – 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 = <STDIN>; 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 "%sn",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 "%sn",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,$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字节的缓冲区,但是为这样的超长线发出一个点.足够我的目的.我还发现我需要在构建输出中允许5分钟的暂停. 解决方法
你有没有试过
File::Tail来处理实际的拖尾而不是试图强迫< STDIN>做这个工作?
或者,如果那件作品确实有效,那么失败的方式是什么? (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |