有状态尾(仅显示上次执行的新行)

时间:2008-10-29 20:15:38

标签: perl tail persistent stateful

我希望能够看到自上次查询以来在文件中添加了多少行而没有再次读取整个文件。

类似的东西:

ptail my_file | fgrep "[ERROR]" | wc -l 

首选简单Perl的解决方案,因为我无法轻松访问编译器。

4 个答案:

答案 0 :(得分:2)

since完全相同,尽管它在C中。

答案 1 :(得分:2)

可能这个Perl包可以帮到你:

File::Tail::Multi

派生自MultiTail,这个perl库可以轻松地使用完整正则表达式来拖动动态文件列表并匹配/除行,甚至可以在本地维护它们的状态。

示例使用File :: Tail :: Multi;

$tail1=File::Tail::Multi->new (  OutputPrefix => "f", 
                                 Debug => "$True", 
                                 Files => ["/var/adm/messages"]
                              );
while(1) {
    $tail1->read;
    #
    $tail1->print;
    sleep 10;
}
  • $tail1=File::Tail::Multi->new:创建新的ptail对象
  • Files =>尾文件/ var / adm / messages
  • OutputPrefix =>在对象属性“LineArray”
  • 中添加每行开头的文件名
  • $tail1->read:从文件中读取所有行
  • $tail1->print:打印对象属性“LineArray”中的所有行;

答案 2 :(得分:2)

虽然它出于其他目的消耗了这些行,但我之前编写的代码基本上都是这样做的。

您需要做的就是在尾部完成后为每个文件记录字节偏移(使用 tell )和inode(使用 stat )。下次对文件运行时,首先再次检查inode(带 stat )。如果inode已更改或文件小于记录的偏移量,则它是一个不同的文件(删除并重新创建,日志被旋转等),因此您应该从头开始显示它;否则,搜索到记录的偏移量并从那里显示。

答案 3 :(得分:2)

我实现了纯Perl版本的最小版本:

#! /usr/bin/perl
# Perl clone of since(1)
# http://welz.org.za/projects/since
#

use strict;
use warnings;

use Fcntl qw/ SEEK_SET O_RDWR O_CREAT /;
use NDBM_File;

my $state_file = "$ENV{HOME}/.psince";

my %states;
tie(%states, 'NDBM_File', $state_file, O_CREAT | O_RDWR, 0660)
        or die("cannot tie state to $state_file : $!");

while (my $filename = shift) {
        if (! -r $filename) {
                # Ignore
                next;
        }
        my @file_stats = stat($filename);
        my $device = $file_stats[0];
        my $inode = $file_stats[1];
        my $size = $file_stats[7];
        my $state_key = $device . "/" .$inode;
        print STDERR "state_key=$state_key\n";

        if (! open(FILE, $filename) ) {
                print STDERR "cannot open $filename : $!";
                next;
        }

        # Reverting to the last cursor position
        my $offset = $states{$state_key} || 0;
        if ($offset <= $size) {
                sysseek(FILE, $offset, SEEK_SET);
        } else {
                # file was truncated, restarting from the beginning
                $offset = 0;
        }

        # Reading until the end
        my $buffer;
        while ((my $read_count = sysread(FILE, $buffer, 4096)) > 0) {
                $offset += $read_count;
                print $buffer;
        }
        # Nothing to read
        close(FILE);
        $states{$state_key} = $offset;
}

# Sync the states
untie(%states);

@Dave:这几乎就像你的算法,除了我不使用告诉,而是使用内部维护的计数器。