【问题标题】:Monitor folder for new files using unix ksh shell script or perl script and trigger perl script使用 unix ksh shell 脚本或 perl 脚本监视文件夹中的新文件并触发 perl 脚本
【发布时间】:2010-12-04 18:30:15
【问题描述】:

我一直在谷歌搜索和溢出,找不到任何可用的东西。

我需要一个脚本来监控公共文件夹并在创建新文件时触发,然后将文件移动到私人位置。

我在 unix 上有一个 samba 共享文件夹 /exam/ple/ 映射到 Windows 上的 X:\。在某些操作中,txt 文件被写入共享。我想绑架文件夹中出现的任何 txt 文件并将其放入 unix 上的私有文件夹 /pri/vate 中。移动该文件后,我想触发一个单独的 perl 脚本。

编辑 如果有人有任何想法,仍在等待查看 shell 脚本......将监视新文件然后运行类似的东西:

#!/bin/ksh
mv -f /exam/ple/*.txt /pri/vate

【问题讨论】:

  • 您需要以编程方式完成,还是可以利用现有设施?这就是 cron 的用途。
  • 新文件可以触发cron吗?
  • 我也不希望 cron 一遍又一遍地运行第二个脚本...我只希望在新文件成功传输到私有文件夹后运行第二个脚本

标签: perl unix shell ksh


【解决方案1】:

检查incron。它似乎完全符合您的需要。

【讨论】:

  • 这看起来相当不错...可惜我无法安装它:
  • 一个很好的 hello world 类型的 incron 示例:errr-online.com/2011/02/25/…
  • incron可以安装在Windows上吗?
【解决方案2】:

如果我理解正确,你只是想要这样的东西?

#!/usr/bin/perl

use strict;
use warnings;

use File::Copy

my $poll_cycle = 5;
my $dest_dir = "/pri/vate";

while (1) {
    sleep $poll_cycle;

    my $dirname = '/exam/ple';

    opendir my $dh, $dirname 
        or die "Can't open directory '$dirname' for reading: $!";

    my @files = readdir $dh;
    closedir $dh;

    if ( grep( !/^[.][.]?$/, @files ) > 0 ) {
        print "Dir is not empty\n";

        foreach my $target (@files) {
            # Move file
            move("$dirname/$target", "$dest_dir/$target");

            # Trigger external Perl script
            system('./my_script.pl');
    }
}

【讨论】:

  • 生病测试一下....这无限运行我猜?另外,我只在寻找文本文件,但是拥有 grep 炸弹很酷
  • @CheeseConQueso:是的,这是一个无限循环,以您指定的频率进行轮询。我没有严格测试代码,但想法很简单。
  • @CheeseConQueso:如果这是您的情况,您显然可以修改 grep 以忽略具有特定后缀的文件。
  • 我怎样才能杀死这个进程,这样它就不会在半夜转动它的*?我希望它从早上 7 点到晚上 10 点运行,然后躲在角落里过夜
  • @CheeseConQueso:如果您想要特定时间的功能,那么最简单的答案可能是删除while 循环和sleep 并将脚本设置为通过cron 运行。您可以指定运行的时间间隔,也可以限制时间。正如庸医所说,这就是 cron 的设计目的。
【解决方案3】:

File::ChangeNotify 允许您监视文件和目录的更改。

https://metacpan.org/pod/File::ChangeNotify

【讨论】:

    【解决方案4】:

    我知道我参加聚会迟到了,但为了完整起见并向未来的访客提供信息;

    #!/bin/ksh
    # Check a File path for any new files
    # And execute another script if any are found
    
    POLLPATH="/path/to/files"
    FILENAME="*.txt" # Or can be a proper filename without wildcards
    ACTION="executeScript.sh argument1 argument2"
    LOCKFILE=`basename $0`.lock
    
    # Make sure we're not running multiple instances of this script
    if [ -e /tmp/$LOCKFILE ] ; then 
         exit 0
    else
         touch /tmp/$LOCKFILE
    fi
    
    # check the dir for the presence of our file
    # if it's there, do something, if not exit
    
    if [ -e $POLLPATH/$FILENAME ] ; then
         exec $ACTION
    else
         rm /tmp/$LOCKFILE
         exit 0
    fi
    

    从 cron 运行它;

    */1 7-22/1 * * * /path/to/poll-script.sh >/dev/null 2>&1

    您希望在后续脚本 ( $ACTION ) 中使用锁定文件,然后在退出时清理它,这样您就不会有任何堆叠进程。

    【讨论】:

      【解决方案5】:
      $ python autocmd.py /exam/ple .txt,.html /pri/vate some_script.pl
      

      优点:

      autocmd.py:

      #!/usr/bin/env python
      """autocmd.py 
      
      Adopted from autocompile.py [1] example.
      
      [1] http://git.dbzteam.org/pyinotify/tree/examples/autocompile.py
      
      Dependencies:
      
      Linux, Python, pyinotify
      """
      import os, shutil, subprocess, sys
      
      import pyinotify
      from pyinotify import log
      
      class Handler(pyinotify.ProcessEvent):
          def my_init(self, **kwargs):
              self.__dict__.update(kwargs)
      
          def process_IN_CLOSE_WRITE(self, event):
              # file was closed, ready to move it
              if event.dir or os.path.splitext(event.name)[1] not in self.extensions:
                 # directory or file with uninteresting extension
                 return # do nothing
      
              try:
                  log.debug('==> moving %s' % event.name)
                  shutil.move(event.pathname, os.path.join(self.destdir, event.name))
                  cmd = self.cmd + [event.name]
                  log.debug("==> calling %s in %s" % (cmd, self.destdir))
                  subprocess.call(cmd, cwd=self.destdir)
              except (IOError, OSError, shutil.Error), e:
                  log.error(e)
      
          def process_default(self, event):
              pass
      
      
      def mainloop(path, handler):
          wm = pyinotify.WatchManager()
          notifier = pyinotify.Notifier(wm, default_proc_fun=handler)
          wm.add_watch(path, pyinotify.ALL_EVENTS, rec=True, auto_add=True)
          log.debug('==> Start monitoring %s (type c^c to exit)' % path)
          notifier.loop()
      
      
      if __name__ == '__main__':
          if len(sys.argv) < 5:
             print >> sys.stderr, "USAGE: %s dir ext[,ext].. destdir cmd [args].." % (
                 os.path.basename(sys.argv[0]),)
             sys.exit(2)
      
          path = sys.argv[1] # dir to monitor
          extensions = set(sys.argv[2].split(','))
          destdir = sys.argv[3]
          cmd = sys.argv[4:]
      
          log.setLevel(10) # verbose
      
          # Blocks monitoring
          mainloop(path, Handler(path=path, destdir=destdir, cmd=cmd,
                                 extensions=extensions))
      

      【讨论】:

      【解决方案6】:

      这将导致相当多的 io - stat() 调用等。如果您想要快速通知而无需运行时开销(但需要更多前期工作),请查看 FAM/dnotify:link textlink text

      【讨论】:

        【解决方案7】:

        我不使用 ksh,但这是我使用 sh 的方法。我敢肯定它很容易适应 ksh。

        #!/bin/sh
        trap 'rm .newer' 0
        touch .newer
        while true; do
          (($(find /exam/ple -maxdepth 1 -newer .newer -type f -name '*.txt' -print \
              -exec mv {} /pri/vate \; | wc -l))) && found-some.pl &
          touch .newer
          sleep 10
        done
        

        【讨论】:

          【解决方案8】:
          #!/bin/ksh
          while true
          do
              for file in `ls /exam/ple/*.txt`
              do
                    # mv -f /exam/ple/*.txt /pri/vate
                    # changed to
                    mv -f  $file  /pri/vate
          
              done
              sleep 30
          done
          

          【讨论】:

          • 这是一种在我在网上找到的 korn shell 中每 30 秒进行一次搜索的方法......它不是由新文件触发的,它更像是一个 cron 类型的进程...... . 我仍然找不到在新文件存在时运行的 korn shell 脚本
          • @Cheese,这是一个有点笨拙的例子 - 如果 /exam/ple 在一次迭代中有两个文件,那么 for 主体将运行两次,但两个文件将首先被 mv'ed时间通过。所以你会在 mv 的第二次调用中看到错误。需要那些反引号吗?
          • @Martin - 好点...我在网上找到它并没有测试它,所以我不确定是否需要反引号。我只是把它放在这里,因为它是一种 shell 方法。 cron 可以做同样的事情也很笨重