Search code examples
perlfileinotify

Perl File::Monitor module notifying multiple notifications for the new file created whereas i expect one notification


Below is the code snippet! i am using for file creatiing notification using Perl module File::Monitor.

#!/usr/bin/perl

use strict;
use warnings;
use File::Monitor;
use File::Basename;
use Time::HiRes qw {usleep};

my $pid,@pids;


sub textfile_notifier {
my ($watch_name, $event, $change) = @_; 

my @new_file_paths = $change->files_created; #The change object has a property called files_created, 
                                             #which contains the names of any new files
for my $path (@new_file_paths) {
    my ($base, $fname, $ext) = fileparse($path, '.log'); # $ext is "" if the '.txt' extension is
                                                         # not found, otherwise it's '.txt'.
    if ($ext eq '.log') {
        print "$path was created\n";
    #-----------------------------------------Forking part #-----------------------------------------
    defined ($pid = fork()) or die "Couldn't fork: $!";
    if ($pid == 0) { #then in child process
        print "Loop got executed\n";
    }
    else {  #then in parent process, where $pid is the pid of the child
        push @pids, $pid;
    }
    #-----------------------------------------Forking part ends here #-----------------------------------------
    }
}
}

my $monitor = File::Monitor->new();

$monitor->watch( {
name        => '/home/goudarsh/Desktop/logs/',
recurse     => 1,
callback    => {files_created => \&textfile_notifier},  #event => handler 1 
} );

$monitor->scan;
while (1) {
$monitor->scan; #Scanning the directory one
#sleep(2);
#usleep(10_000); #$microseconds = 750_000;
for my $pid (@pids) {
    waitpid($pid, 0)  #0 => block
}
}

file creation

=============================

touch 1.log  
touch 2.log  
touch 3.log  
touch 4.log  

output of the script

=========================

/home/goudarsh/Desktop/logs/1.log was created  
/home/goudarsh/Desktop/logs/2.log was created  
/home/goudarsh/Desktop/logs/2.log was created  
/home/goudarsh/Desktop/logs/3.log was created  
/home/goudarsh/Desktop/logs/3.log was created  
/home/goudarsh/Desktop/logs/3.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/3.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/4.log was created  
/home/goudarsh/Desktop/logs/4.log was created      

Where as i am expecting one notification/alert printed for one file on the terminal. what i suspect is that there is some bug in the "Forking part" section!

any idea where's i am doing wrong ?


Solution

  • Here's what solved my problem

    use strict;
    use warnings;
    use File::Monitor;
    use File::Basename;
    use Time::HiRes qw {usleep};
    my $script = '/homw/goudarsh/Desktop/script.pl';
    sub textfile_notifier {
    my ($watch_name, $event, $change) = @_; 
    
    my @new_file_paths = $change->files_created; #The change object has a property called files_created, 
                                             #which contains the names of any new files
    for my $path (@new_file_paths) {
    my ($base, $fname, $ext) = fileparse($path, '.log'); # $ext is "" if the '.txt' extension is
                                                         # not found, otherwise it's '.txt'.
    if ($ext eq '.log') {
        print "$path was created\n";
        system("perl $script $path \&");
    }
    }}
    my $monitor = File::Monitor->new();
    $monitor->watch( {
    name        => '/home/goudarsh/Desktop/logs/',
    recurse     => 1,
    callback    => {files_created => \&textfile_notifier},  #event => handler 1 
    } );
    
    $monitor->scan;
    while (1) {
    $monitor->scan; #Scanning the directory one
    sleep(2);
    #usleep(10_000); #$microseconds = 750_000;
    
    }
    

    All i wanted to execute a $script with $path as an argument and i used forking for creating child process but i was wrong about the concept of using fork which was not needed! now without forking i can do whatever was required and i am happy for learning new things