监视目录树的更改
1. 概述
在本教程中,我们将学习如何使用inotifywait 来监视目录树的更改。例如,我们将了解如何检测新文件何时创建。
我们将从对问题的介绍开始。然后,我们将了解inotify 事件。最后,我们将讨论inotifywait命令以及如何使用它来解决问题。
2. 依赖
由于我们的示例将使用inotifywait命令,因此我们需要确保它已安装。如果没有安装,我们可以通过安装inotify-tools 包来添加它。如果我们有 Debian 发行版或类似发行版,我们可以以 root 身份运行apt-get 命令来安装软件包:
$ apt-get install inotify-tools
另一方面,如果我们有 Red Hat 发行版或类似发行版,我们可以使用yum 命令,但首先,我们必须安装epel-release 存储库:
$ yum install epel-release
$ yum install inotify-tools
3. 问题介绍
让我们从一个名为main的目录开始,它包含几个子目录。使用*tree 命令,我们可以看到我们的main*目录树:
$ tree main/
main/
├── 1
│ ├── 1
│ └── 2
│ └── 1
├── 2
└── 3
├── 1
└── 2
└── 1
└── 1
10 directories, 0 files
**首先,我们将监控这个目录树。**例如,我们可以知道文件何时被创建或删除、打开、写入、读取或关闭。**然后,当我们在此目录树上检测到事件时,我们将使用此信息来运行其他程序。**例如,我们可以在进程删除此目录树中的文件时提醒用户。
4. 了解inotify事件
在 Linux 中,我们可以使用inotify接口来监控目录或文件。我们通过向目录或文件添加监视来做到这一点。当我们向文件添加监视时,我们可以对其进行监视。例如,我们将知道进程何时打开、修改、读取关闭、移动或删除文件。
当我们向目录添加监视时,我们还监视该目录中任何文件中的事件。此外,我们可以知道另一个进程是否在该目录中创建、删除或移动文件。我们可以选择监视所有事件或仅监视其中一些事件。当任何这些事件发生时,系统会通知我们。
5. 使用inotifywait
*我们可以使用inotifywait命令来监控目录树。要监视目录树,包括其子目录,我们将使用-r参数。此外,我们必须使用-m参数。这将inotifywait配置为永远监视目录。否则,inotifywait在第一个事件之后退出。**让我们看看如何监控主*目录中的任何事件:
$ inotifywait -m -r main
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
这样,inotifywait命令将继续在前台运行,等待事件。现在,当inotifywait仍在运行时,让我们打开一个新的 shell 并运行echo example > main/1/2/file1。此命令在main/1/2文件夹中创建一个新文件。让我们返回到运行inotifywait的 shell以查看其输出:
main/1/2/ CREATE file1
main/1/2/ OPEN file1
main/1/2/ MODIFY file1
main/1/2/ CLOSE_WRITE,CLOSE file1
我们可以看到inotifywait输出有三列。首先是基目录,然后是事件,最后是触发该事件的文件。现在,让我们在main/2目录中创建一个名为1的新文件夹。然后,我们将在新目录中创建一个名为file1的新文件:
$ mkdir main/2/1
$ echo example > main/2/1/file1
让我们看看inotifywait的输出:
main/2/ CREATE,ISDIR 1
main/2/ OPEN,ISDIR 1
main/2/ ACCESS,ISDIR 1
main/2/ CLOSE_NOWRITE,CLOSE,ISDIR 1
main/2/1/ CREATE file1
main/2/1/ OPEN file1
main/2/1/ MODIFY file1
main/2/1/ CLOSE_WRITE,CLOSE file1
我们可以注意到inotifywait 会自动监视新目录中的事件。**最后,让我们看看如何指定我们想要监控的确切事件。*为此,我们将使用-e*参数并添加以逗号分隔的所需事件。
首先,让我们用Control+C完成前面的inotifywait命令。然后,让我们只监视创建和修改事件:
$ inotifywait -m -r -e create,modify main
现在,让我们写入main/1/2/file1文件,然后在main/1/2目录中创建一个名为**file2的新空文件:
$ echo example2 >> main/1/2/file1
$ touch main/1/2/file2
让我们看看新的输出:
main/1/2/ MODIFY file1
main/1/2/ CREATE file2
6. 将inotifywait输出与另一个脚本集成
到目前为止,我们已经学会了如何使用inotifywait。所以现在,让我们根据inotifywait报告的事件创建一个脚本来运行另一个程序。
首先,让我们编写一个运行xmessage 的函数来通知用户文件已被删除:
$ file_removed() {
xmessage "$2 was removed from $1" &
}
该函数接收两个参数。第一个是目录,另一个是删除的文件。此外,我们将在后台运行xmessage,因此该函数不会阻塞。然后,让我们编写两个函数来在文件被修改和创建时写入日志文件:
$ file_modified() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was modified" >> monitor_log
}
$ file_created() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was created" >> monitor_log
}
现在,我们可以解析inotifywait输出并将其提供给 while 循环。我们将使用read命令从输出中拆分目录、事件和文件字段。
接下来,我们可以使用case命令根据事件来决定调用哪个函数。此外,我们将在inotifywait命令中添加*-q参数,以便inotifywait仅打印事件而不打印初始消息。让我们将所有这些放在一个名为monitor_directory_tree.sh* 的脚本中。脚本接收要监视的目录作为第一个参数。然后在inotifywait上报事件时调用相应的函数:
#!/bin/bash
file_removed() {
xmessage "$2 was removed from $1" &
}
file_modified() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was modified" >> monitor_log
}
file_created() {
TIMESTAMP=`date`
echo "[$TIMESTAMP]: The file $1$2 was created" >> monitor_log
}
inotifywait -q -m -r -e modify,delete,create $1 | while read DIRECTORY EVENT FILE; do
case $EVENT in
MODIFY*)
file_modified "$DIRECTORY" "$FILE"
;;
CREATE*)
file_created "$DIRECTORY" "$FILE"
;;
DELETE*)
file_removed "$DIRECTORY" "$FILE"
;;
esac
done
让我们首先在后台运行monitor_directory_tree.sh来测试这个脚本。然后我们将删除main/3/2/1目录。接下来,我们将一些文本写入main/1/2/file1文件。最后,我们将创建并写入main/file1文件:
$ ./monitor_directory_tree.sh main &
[1] 4800
$ rm -r main/3/2/1
$ echo example >> main/1/2/file1
$ echo example >> main/file1
有了这个,我们可以注意到出现了两个xmessage警报。一个警报说“从 main/3/2/1 中删除了 1”,另一个警报说“从 main/3/2 中删除了 1”。这是因为当我们运行rm -r main/3/2/1 时,它还删除了main/3/2/1/1子目录。现在,让我们看一下monitor_log文件:
$ cat monitor_log
[Tue Sep 21 21:49:31 -03 2021]: The file main/1/2/file1 was modified
[Wed Sep 21 21:49:34 -03 2021]: The file main/file1 was created
[Wed Sep 21 21:49:34 -03 2021]: The file main/file1 was modified
我们可以看到,日志显示我们修改了main/1/2/file1。然后它显示文件main/file1已创建和修改,就像我们一样。