代码之家  ›  专栏  ›  技术社区  ›  Steve Schnepp

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

  •  5
  • Steve Schnepp  · 技术社区  · 16 年前

    我希望能够看到自上次查询以来有多少行被添加到一个文件中,而不需要再次读取整个文件。

    比如:

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

    最好使用简单Perl的解决方案,因为我不容易访问编译器。

    4 回复  |  直到 16 年前
        1
  •  2
  •   Dave Sherohman    16 年前

    虽然它将这些行用于其他目的,但我已经编写了一些代码,这些代码在以前基本上都是这样做的。

    您需要做的就是记录字节偏移量(用 告诉 )和inode(与 斯达 )对于每个文件,在尾部完成之后。下次对文件运行时,首先检查inode 斯达 又一次。如果inode已更改或文件小于记录的偏移量,则它是另一个文件(已删除并重新创建,日志已旋转等),因此应从头显示它;否则, 寻求 到记录的偏移并从那里显示。

        2
  •  2
  •   Steve Schnepp    16 年前

    since 确实如此,尽管它是在C。

        3
  •  2
  •   VonC    16 年前

    可能这个Perl包可以帮助您:

    File::Tail::Multi

    这个Perl库是从multitail派生的,它使用完整的正则表达式很容易跟踪文件的动态列表和匹配/排除行,甚至在本地维护它们的状态。

    示例使用文件::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”中的所有行;
        4
  •  2
  •   Steve Schnepp    16 年前

    我实现了纯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);
    

    @戴夫:这和你的算法差不多,只是我不使用 告诉 但是内部维护的计数器。