腾讯云

让您的 VPS 更具响应性:使用 python-inotify 轻松编写在文件系统事件发生时自动触发的脚本

—

自动运行程序的能力是计算机最伟大的解放力量之一。在 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,以便在创建新文件时做任何你想做的事情。尽情享受吧!