自动运行程序的能力是计算机最伟大的解放力量之一。在 Unix 中,用户通常使用 cron 或 at(或使用 systemd 的 timers)来调度任务。但如果你想要运行一个任务不是基于时间表,而是响应某个事件呢?
想象你有一个目录,每当你向该目录放入一个文件时,你希望它被压缩并放入备份目录。或者你有一个“共享”目录,人们可以上传图片,(在测试它是否真的是图片之后)你自动将它们移动到你的 Web 目录并添加到你的托管中。或者你有一个复杂的备份系统,在启动后,它会在某个位置放置一个标志文件。
在过去,人们会编写每分钟运行的 cron 任务来检查文件是否存在等等。这些方法粗糙、资源密集,而且经常容易出错——例如,你必须防止这些频繁运行的脚本的多个副本同时执行。
在 Linux 中,我们可以使用 inotify(inode 通知),它能在非常细粒度的级别上对文件系统变化做出反应。通常,你会创建一个守护进程,设置文件系统监视,在后台运行,并通过调用某些代码或触发脚本来响应事件。
有几种使用 inotify 的方式:
如果你是一名内核程序员,可以使用 C API。
有两个命令行程序(inotifywatch 和 inotifywait,属于 Debian 中 inotify-tools 包的一部分)。我觉得它们不太有用。inotifywatch 收集统计信息,而 inotifywait 只是等待文件系统事件发生。inotifywait 确实有一个守护进程选项,但仅限于将事件记录到文件。
Python 有一个 inotify 模块,非常适合编写守护进程。
安装 Python 的 inotify
在 Debian 13 上安装该模块很容易:
使用 Python 的 inotify
让我们从一个示例脚本开始,以便你了解 inotify 的用法。该脚本监视目录 /tmp/test,并响应其中发生的文件更改事件。首先,设置测试:
现在将以下内容放入一个名为 test_inotify.py 的文件中:
注意:因为这是 Python,请确保缩进的行使用单个 TAB 字符缩进。
现在执行它:
最初,什么都不会发生。现在打开第二个会话连接到你的 VPS,并在该目录中执行一些文件系统命令。你会看到事件在我们创建、填充、chmod 和删除文件时触发:
你可以按 control-C 来停止 test_inotify.py
如你所见,每次更改都会触发一个或多个事件。有些操作(如 touch 一个文件(创建它))会触发多个事件。
创建一个基于 inotify 的守护进程
让我们做一些更有用的事情。我们将创建一个守护进程,可以在系统启动时通过 systemd 启动它,并通过调用 shell 脚本来响应事件。这只是一个你可以采用并扩展的骨架。
首先,安装 Python 的 daemonize 模块:
在 /usr/local/bin 中,创建以下文件为 watchfs.py:
如果这对你来说像天书一样,别担心。你需要修改以自定义它的唯一几行是在 CONFIG 和 END_CONFIG 之间的行:
你想监视哪个目录(directory_to_watch)
你想调用哪个脚本作为响应(/usr/local/bin/react.sh)
你想监视哪个文件系统事件(这里,IN_CREATE)
这个脚本所做的只是将文件名写入 /tmp/reaction.log。你可以轻松扩展它,用它接收到的文件名做任何你想做的事情。
使两个文件都可执行:
让我们在 systemd 中设置它。将以下文件放在 /etc/systemd/system/watchfs.service:
现在:
让我们测试一下:
这是一个基本示例,但你应该清楚如何自定义它并扩展到更多监视。由于它只是调用一个 shell 脚本,你可以调整 react.sh,以便在创建新文件时做任何你想做的事情。尽情享受吧!
