在Linux中监视一个目录以获取新文件,然后运行脚本。

13

我想在Ubuntu 14.04上监视一个目录,当该目录中创建了新文件时运行一个脚本。

具体来说,我有一些安全摄像头,它们在检测到运动时通过FTP上传捕获的视频。我想在FTP服务器上运行一个脚本,以便当新文件创建时,立即将其镜像(上传)到云存储服务中,这已经通过我编写的脚本完成。

我找到了iWatch可以实现这个功能(http://iwatch.sourceforge.net/index.html)-我的问题在于,iWatch在文件被创建时立即启动云上传脚本,即使文件正在上传过程中仍然会触发。这会导致云同步脚本上传0字节的文件,对我没有任何用处。

也许我可以在云上传脚本中添加一个“等待”的操作,但这似乎很不专业,并且很难预测需要等待多长时间,因为这取决于文件大小、网络条件等因素。

有更好的方法吗?

3个回答

18

虽然评论中提到了inotifywait,但为他人提供完整的解决方案可能会更有用。以下方法似乎可行:

Although inotifywait was mentioned in comments, a complete solution might be useful to others. This seems to be working:

 inotifywait -m -e close_write /tmp/upload/ | gawk '{print $1$3; fflush()}' | xargs -L 1 yourCommandHere

将会运行

  yourCommandHere /tmp/upload/filename

当一个新上传的文件被关闭时

注意:

  • inotifywait 是 Ubuntu 中 apt 包 inotify-tools 的一部分。它使用内核 inotify 服务监视文件或目录事件。
  • -m选项是监视模式,每个事件输出一行到stdout
  • -e close_write用于文件关闭事件,对于写打开的文件。希望文件关闭事件避免接收到不完整的文件。
  • /tmp/upload可以替换为其他要监视的目录
  • 管道传输给gawk重新格式化inotifywait输出行,删除第二列,即事件类型的重复。将第一列中的 dirname 与第三列中的 filename 组合成新行,每行都被清除以消除缓冲并鼓励 xargs 立即执行。
  • xargs 获取文件列表并为每个文件运行给定的命令,在命令末尾添加文件名。 -L 1使xargs在接收到标准输入的每一行后运行。

一个完美的答案!感谢您的努力。 - Nikolai Koudelia

1
你离解决方案很近了。你可以使用iwatch观看许多不同的事件,其中一个感兴趣的是close_write。语法:
iwatch -e close_write <directory_name>

当写入完成时,文件关闭,这当然只有在文件关闭时才适用,这是一个合理的假设,但不一定是真实的(尽管经常如此)。

谢谢,我也尝试过了。在上传脚本中使用inotifywait -e close_write作为“等待”的方式进行了尝试。不幸的是,两种方法都没有按预期工作。我猜这是因为上传到vsftpd的文件由于某些原因没有被正确地“关闭”或“close_write”。我可能会尝试一些hack-y的东西,比如对文件执行'ls -al'并等待X秒,直到文件大小停止变化,然后继续。虽然这似乎是一个可怕的解决方案。 - Noob on Mac
目前我决定不按照原计划,即在文件上传到FTP后立即进行云同步,而是运行一个每小时一次的cron作业,如果它没有看到已经存在的文件,则将文件上传到云存储。因此,这是一个可接受但不太理想的解决方法。 - Noob on Mac

0
这是另一种通过向给定的URL发出POST请求来响应文件系统事件的版本。
#!/bin/bash
set -euo pipefail
cd "$(dirname "$0")"

watchRoot=$1
uri=$2

function post()
{
    while read path action file; do
        echo '{"Directory": "", "File": ""}' |
        jq ".Directory |= \"$path\"" |
        jq ".File |= \"$file\"" |
        curl --data-binary @- -H 'Content-Type: application/json' -X POST $uri || continue
    done
}

inotifywait -r -m -e close_write "$watchRoot" | post

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接