如何监视 Linux 上文件和目录的文件系统事件
Inode notify (inotify) 是一个 Linux 内核子系统,它提供 API 来监视文件系统事件。除了通过适当的编程语言与此类 API 进行通信之外,还可以通过使用一些明确设计的命令行工具(例如 inotifywait)来利用公开的功能,该工具可以轻松安装在所有主要 Linux 发行版中。
在本教程中,我们将了解如何安装和使用 inotifywait 实用程序来监视 Linux 上的文件系统事件。
在本教程中您将学习:
如何在一些最常用的 Linux 发行版上安装 inotifywait
如何使用 inotifywait 监视文件和目录上的文件系统事件
如何监控特定事件
安装
inotifywait 命令行实用程序是 inotify-tools 软件包的一部分,该软件包可在所有主要 Linux 发行版的官方存储库中找到。要在 Fedora 和基于 Fedora 的发行版上安装该软件包,我们运行:
$ sudo dnf install inotify-tools
要在 Debian 及其衍生版本上安装它,我们可以使用以下命令:
$ sudo apt install inotify-tools
该软件包还可以在“Extra”Archilinux 存储库中找到。我们可以使用 pacman 包管理器来执行安装:
$ sudo pacman -Sy inotify-tools
监控文件系统事件
inotifywait 实用程序可用于等待文件系统事件并对其做出反应。在最简单的用法中,我们调用该实用程序并传递我们想要监视的文件或目录的路径作为参数。在下面的示例中,我们以 ~/.bash_profile
文件为例:
$ inotifywait ~/.bash_profile
Setting up watches.
Watches established.
当按照我们上面的方式执行时,该工具会在指定文件上建立一个监视,并在第一个事件发生时存在。举个例子,让我们尝试读取文件的内容:
$ cat ~/.bash_profile
一旦我们从另一个终端窗口启动命令,我们就会收到“OPEN”事件的通知,并且 inotify 退出:
/home/doc/.bash_profile OPEN
如果我们将目录路径作为参数传递给命令,则将监视该目录内的所有文件;但是,不是子目录的内容,因为默认情况下该命令不是递归的。要更改此行为并监视整个目录树,我们所要做的就是使用 -r
(--recursive
) 选项。以这种方式运行实用程序时,我们可能必须增加允许的监视的最大数量,这可以通过将适当的值写入 /proc/sys/fs/inotify/max_user_watches
文件来完成。但请注意,重新启动时不会保留对文件的更改。查看本教程以了解如何使它们永久化。
监听特定事件
在某些情况下,我们可能希望仅在文件上发生某些特定事件时收到通知。在这种情况下,我们可以简单地使用 -e
(--event
的缩写)选项,并将受支持的事件之一作为参数传递。继续前面的示例,要仅监视 ~/.bash_profile
文件上的“修改”事件,我们将运行:
$ inotifywait -e modify ~/.bash_profile
由于我们只监听“修改”事件,因此如果我们读取文件的内容,该命令将继续运行,但一旦我们尝试写入文件,该命令就会通知我们,就像简单地附加一些内容时一样:
$ echo "# This is just a comment" >> ~/.bash_profile
该事件按预期通知:
/home/doc/.bash_profile MODIFY
我们可以监听的事件如下表所示,如实用程序手册中所述。下面列出了事件并给出了它们的描述。
- access
- 读取监视文件或监视目录中的文件。
- modify
- 已写入监视文件或监视目录中的文件。
- attrib
- 监视的文件或监视的目录中的文件的元数据被修改。这包括时间戳、文件权限、扩展属性等。
- close_write
- 监视的文件或监视目录中的文件在以可写模式打开后被关闭。这并不一定意味着该文件已被写入。
- close_nowrite
- 监视的文件或监视目录中的文件在以只读模式打开后被关闭。
- close
- 监视的文件或监视目录中的文件被关闭,无论它是如何打开的。请注意,这实际上是通过监听 close_write 和 close_nowrite 来实现的,因此收到的所有关闭事件都将作为其中之一输出,而不是 CLOSE。
- open
- 打开了监视的文件或监视目录中的文件。
- moved_to
- 文件或目录已移至监视目录中。即使文件只是从同一目录移动到同一目录,也会发生此事件。
- moved_from
- 文件或目录已从监视目录中移出。即使文件只是从同一目录移动到同一目录,也会发生此事件。
- move
- 文件或目录已从监视目录移出或移至监视目录。请注意,这实际上是通过侦听 moving_to 和 moving_from 来实现的,因此收到的所有关闭事件都将作为其中之一或两者输出,而不是 MOVE。
- move_self
- 监视的文件或目录已移动。在此事件之后,将不再监视该文件或目录。
- create
- 在监视的目录中创建了文件或目录。
- delete
- 监视目录中的文件或目录已被删除。
- delete_self
- 监视的文件或目录被删除。在此事件之后,将不再监视文件或目录。请注意,即使没有显式侦听此事件,也可能会发生该事件。
- unmount
- 监视的文件或目录所在的文件系统已卸载。在此事件之后,将不再监视文件或目录。请注意,即使没有显式侦听此事件,也可能会发生该事件。
以“监听”模式收听
在前面的示例中,我们看到默认情况下,一旦发生受监视的事件之一,使用 inotifywait 建立的监视就会立即存在。 如果我们希望命令继续监听事件,我们可以简单地使用-m
选项,它是--monitor
的缩写形式。
在下面的示例中,我们以监视模式对目标文件建立一个监视,然后,我们首先读取其内容,然后向其附加一些内容。每个操作涉及三个事件,所有这些事件都会被记录:
$ inotifywait -m ~/.bash_profile
Setting up watches.
Watches established.
/home/doc/.bash_profile OPEN # The file is opened
/home/doc/.bash_profile ACCESS # The file is read
/home/doc/.bash_profile CLOSE_NOWRITE,CLOSE # The file is closed after being opened in read-only mode
/home/doc/.bash_profile OPEN # The file is opened
/home/doc/.bash_profile MODIFY # The file is modified (we appended content to it)
/home/doc/.bash_profile CLOSE_WRITE,CLOSE # The file is closed after being opened in writable mode
将文件排除在监视之外
正如我们已经说过的,inotifywait 实用程序可用于侦听指定目录内的文件或整个目录树上的事件。在这种情况下,我们可能希望避免监视特定文件,或明确包含其中的一些文件。为了完成此类任务,我们可以分别使用 --exclude
和 --include
选项。它们都采用 POSIX 正则表达式作为参数。
在下面的示例中,我们监控 ~/.config
目录下的所有文件,除了那些带有“.xml”扩展名的文件:
$ inotifywait -m ~/.config --exclude ".*.xml"
--include
和 --exclude
选项在区分大小写的模式下匹配传递的表达式;然而,两者都有一个在不区分大小写模式下工作的变体:分别是--includei
和--excludei
。
结论
在本教程中,我们学习了如何在一些最常用的 Linux 发行版上安装 inotify-tools 软件包,以及如何使用 inotifywait 命令行实用程序来监视文件和目录上发生的事件。