Reading a file when someone writes to it

Viewed 139

The script reads the lines from the file, here's the code:

#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;

open my $fh, '<', 'input.txt' or die "Can't open file: $!";

my $cv = AE::cv;

my $timer = AE::timer 0, 10, sub {
    printf "TELL: %s EOF: %s\n", tell $fh, eof $fh;
    print while <$fh>;
};

$cv->recv;

If I add lines through cat, then the script reads the new lines. But if I edit the file through a vim editor, then the script does not see any new lines in the file and issues an EOF. Why does the script behave this way and do not see new lines?

Output of the script:

$ perl test.pl
TELL: 0 EOF:
row_1
row_2
row_3
TELL: 18 EOF: 1
TELL: 18 EOF: 1
TELL: 18 EOF:
row_4
TELL: 24 EOF:
row_5
TELL: 30 EOF: 1
TELL: 30 EOF: 1
TELL: 30 EOF: 1
TELL: 30 EOF: 1

The initial content of the input.txt:

row_1
row_2
row_3

Added via cat:

$ cat >> input.txt
row_4
row_5

Added via vim:

$ vim input.txt
row_6
row_7
1 Answers

The shell's >> directive opens the existing file, while vim creates a new file with the same name as the old one, leaving your program reading an a now-anonymous file.

$ touch a

$ perl -MFile::stat -e'my $qfn = $ARGV[0]; my $s = stat($qfn) or die $!; printf "%s:%s\n", $s->dev, $s->ino' a
2065:1084527165

$ cat >>a
foo

$ perl -MFile::stat -e'my $qfn = $ARGV[0]; my $s = stat($qfn) or die $!; printf "%s:%s\n", $s->dev, $s->ino' a
2065:1084527165

$ vim a

$ perl -MFile::stat -e'my $qfn = $ARGV[0]; my $s = stat($qfn) or die $!; printf "%s:%s\n", $s->dev, $s->ino' a
2065:1084520254

You need to re-open the file.

#!/usr/bin/perl
use strict;
use warnings;
use AnyEvent;
use Fcntl qw( SEEK_SET );

my $cv = AE::cv;

my $qfn = $ARGV[0];
my $last_pos = 0;

my $timer = AE::timer 0, 10, sub {
    open(my $fh, '<', $qfn)
        or die("Can't open file: $!\n");
    seek($fh, $last_pos, SEEK_SET)
        or die("Can't seek: $!\n");

    printf "TELL: %s EOF: %s\n", tell $fh, eof $fh;

    print while <$fh>;

    ( $last_pos = tell($fh) ) >= 0
        or die("Can't tell: $!\n");
};

$cv->recv;

Outputs:

$ echo foo >a

$ perl a.pl a
TELL: 0 EOF:
foo
TELL: 4 EOF: 1
TELL: 4 EOF: 1        echo bar >>foo
TELL: 4 EOF:
bar
TELL: 8 EOF: 1
TELL: 8 EOF: 1        Used vim to change the file to "The quick brown fox"
TELL: 8 EOF:
k brown fox
TELL: 20 EOF: 1
^C
Related