在 perl 中使用 inotify 监视多个文件

Posted

技术标签:

【中文标题】在 perl 中使用 inotify 监视多个文件【英文标题】:Watching multiple files with inotify in perl 【发布时间】:2011-03-15 18:18:05 【问题描述】:

我需要在 Perl 中查看多个文件,并且我正在使用 Linux::Inotify2。但是我遇到了一个问题,即需要修改并点击正在观看的第一个文件,然后是第二个,然后是第一个等

例如,如果第二个文件在第一个文件之前更改,它将不会触发,或者如果第一个文件连续触发两次,而第二个文件在两者之间没有被触发。

这是我正在使用的有此问题的代码部分。

my $inotify = new Linux::Inotify2;
my $inotify2 = new Linux::Inotify2;
$inotify->watch ("/tmp/rules.txt", IN_MODIFY);
$inotify2->watch ("/tmp/csvrules.out", IN_MODIFY);

while () 
  my @events = $inotify->read;
  unless (@events > 0)
    print "read error: $!";
    last ;
  

  foreach $mask (@events) 
    printf "mask\t%d\n", $mask;

    open (WWWRULES, "/tmp/rules.txt");

    my @lines = <WWWRULES>;
    foreach $line (@lines) 
      @things = split(/,/, $line);
      addrule(@things[0], @things[1], @things[2], @things[3], trim(@things[4]));
      print "PRINTING: @things[0], @things[1], @things[2], @things[3], @things[4]";
      close (WWWRULES);
      open (WWWRULES, ">/tmp/rules.txt");
      close (WWWRULES);
    
  

  my @events2 = $inotify2->read;
  unless (@events2 > 0)
    print "read error: $!";
    last ;
  
  foreach $mask (@events) 
    printf "mask\t%d\n", $mask;
    open (SNORTRULES, "/tmp/csvrules.out");

    my @lines2 = <SNORTRULES>;
    foreach $line2 (@lines2) 
      @things2 = split(/,/, $line2);
      addrule("INPUT", @things2[0], @things2[1], @things2[2], trim(@things2[3]));
      print "PRINTING: INPUT, @things2[0], @things2[1], @things2[2], @things2[3]";

      close (SNORTRULES);
      open (SNORTRULES, ">/tmp/csvrules.out");
      close (SNORTRULES);
    
  

理想情况下,我想观看 3 个文件,但由于我无法让 2 个文件正常工作,现阶段似乎有点毫无意义。

感谢您的帮助!

【问题讨论】:

【参考方案1】:

单个 inotify 对象可以处理任意数量的手表。这是 inotify 相对于旧的和现在已过时的 dnotify 的优势之一。所以你应该说:

my $inotify = Linux::Inotify2->new;
$inotify->watch("/tmp/rules.txt", IN_MODIFY);
$inotify->watch("/tmp/csvrules.out", IN_MODIFY);

然后你可以通过查看事件对象的fullname属性来查看是哪个watch被触发了:

while () 
  my @events = $inotify->read;
  unless (@events > 0)
    print "read error: $!";
    last ;
  

  foreach my $event (@events) 
    print $event->fullname . " was modified\n" if $event->IN_MODIFY;
  

最大的问题是您的代码正在修改您正在观察修改的相同文件。当/tmp/rules.txt被修改时,你打开它,阅读它,然后截断它,这会触发另一个修改通知,重新开始整个过程​​。一般来说,如果没有竞争条件,这很难解决,但在你的情况下,你应该能够只检查一个空文件 (next if -z $event-&gt;fullname)。

【讨论】:

其实按手柄的手表数量是有限制的。此限制在 /proc/sys/fs/inotify/max_user_watches 中设置【参考方案2】:

您似乎正在对您希望并行发生的事情进行串行检查。您要么想要分叉一个单独的进程,使用线程,要么将其与 POE 对象集成。

另一个可能对您的应用程序有效也可能无效的选项是将您的 tempdir 设置为更具体的内容,并将您正在处理的所有文件保留在其中,然后只观察整个目录,然后如果我没看错的话,只需要 1 个 inotify 对象。 (我还没有对这个模块做任何特别的事情,但是通过将系统调用挂钩到文件系统,我对它的工作原理有了一个很好的了解)。

【讨论】:

如果我观察一个目录,我能否确定该目录中的哪个文件被修改,以便我可以根据哪个文件被更改来采取行动? 我不是 100% 确定,但似乎你应该能够做到。除非我弄错了,否则仍应为目录中的文件引发 IN_ACCESS 事件。

以上是关于在 perl 中使用 inotify 监视多个文件的主要内容,如果未能解决你的问题,请参考以下文章

c++ inotify - 监视多个目录/子目录

Perl inotify2 每次文件修改触发两次

C程序使用inotify监视多个目录以及子目录?

如何在c中使用inotify查看具有多个文件更改的目录

如何监视文件并在终端中打印出更改(使用 inotify)?

使用 inotify 检查监视文件夹中的文件是不是被覆盖