如何在 Linux 中监视完整的目录树的更改?

Posted

技术标签:

【中文标题】如何在 Linux 中监视完整的目录树的更改?【英文标题】:How to monitor a complete directory tree for changes in Linux? 【发布时间】:2012-01-31 17:26:42 【问题描述】:

我如何监控整个目录树在 Linux(ext3 文件系统)中的变化?

目前该目录包含大约 50 万个文件,分布在大约 3,000 个子目录中,分为三个目录级别。

这些文件大多是小文件(

我知道有 inotify 和排序,但 AFAIK 他们只监控一个目录,这意味着我需要 3,000 个 inotify 句柄 - 比单个进程允许的通常 1024 个句柄多.还是我错了?

万一Linux系统不能告诉我我需要什么:也许有一个FUSE项目模拟文件系统(复制真实文件系统上的所有文件访问)并单独记录所有修改(一个都不好)?

【问题讨论】:

【参考方案1】:

我使用inotifywait 工具做了类似的事情:

#!/bin/bash
while true; do

inotifywait -e modify,create,delete -r /path/to/your/dir && \
<some command to execute when a file event is recorded>

done

这将在整个树上设置递归目录监视,并允许您在发生变化时执行命令。如果您只想查看更改,可以添加-m 标志使其进入监控模式。

【讨论】:

要避免while loop,请使用-m--monitor 开关/选项/标志/参数。不知道那个“开关”是什么时候出现的,但比循环更好 您还应该添加move 事件:inotifywait -e modify,create,delete,move -r /path/to/your/dir 这种方法不会错过一个事件,以防其中两个事件在一瞬间发生?在 inotifywait 存在之后,会有一段时间没有事件被监控,不是吗? @gwillie,但如果使用m 标志,它只会输出到stdout,我们无法使用该触发器执行任何命令。那么,如果你想在观察到任何事件后执行某些事情,while 循环不是更好吗?【参考方案2】:
$ inotifywait -m -r /path/to/your/directory

此命令足以递归地监视目录中的所有事件,例如访问、打开、创建、删除...

【讨论】:

是的,但是诸如访问和打开之类的事件非常有问题。取决于你的意图是什么。示例:每次 www 目录中发生更改时,我都想重新启动 cordova run。结果,cordova 生成的开放访问事件触发了 inotifywait,进入了无限循环。 -e modify,create,delete,move 更适合大多数用途。【参考方案3】:

据我所知,除了在每个目录上递归设置 inotify 监视之外别无他法。

也就是说,您不会用完文件描述符,因为inotify 不必保留 fd 来监视文件或目录(其前身 dnotify 确实受到此限制)。 inotify 改用“监视描述符”。

根据inotifywatch 的文档,默认限制是8192 个监视描述符,您可以通过将新值写入/proc/sys/fs/inotify/max_user_watches 来增加它。

【讨论】:

听起来不错。使用这么多手表描述符时需要考虑哪些负面因素? 不,除了创建所有手表所花费的时间之外,我认为您不会遇到只有 3000 个子目录的问题。 这不会造成可能的种族问题,例如:在folder_main 中创建folder_sub,在folder_sub 中创建folder_sub_subfolder_main 的inotify 到达,手表设置在folder_sub ,但是folder_sub_sub已经错过了,所以上面还没有安装手表? Ubuntu 18.04 现在将默认值“max_user_watches”设置为 65536,这在普通桌面/服务器系统中似乎是一个合理的值。【参考方案4】:

当你有很多子目录时,inotify 是最好的选择,但如果不是,我习惯使用下面的这个命令:

watch -d find &lt;&lt;path&gt;&gt;

【讨论】:

手表是首选 watch 不允许分页,因此它会丢失任何比终端高度长的东西(例如,tree 文件数 > 终端行数的命令) 我很想看到支持find 每 5-10 秒处理 50 万个文件的硬件(以及该方法对其工作负载的影响)。 ...如果我是您的系统管理员并且看到您制造这种负载,我会追捕您并与您进行非常严厉的谈话。 @tink 当然,如果您有很多文件要检查,那么多次运行find 不是可行的方法。我的回答可以帮助那些想要检查子目录但无权访问inotify 的人。正如我建议的那样,inotify 是当你有很多文件时最好的选择。【参考方案5】:

使用 inotify-tools 中的 inotifywait:

sudo apt install inotify-tools

现在创建一个包含隐藏文件和文件夹的脚本myscript.sh

#!/bin/bash
while true; do

inotifywait -e modify,create,delete,move -r $1

done

使用chmod +x myscript.sh使脚本可执行

使用./myscript.sh /folder/to/monitor 运行它

如果你不提供参数,它将默认使用工作目录。

另外,您可以运行多个命令,在上一条命令末尾添加&amp;&amp; \ 以添加下一条:

#!/bin/bash
while true; do

inotifywait -e modify,create,delete,move -r $1 && \
echo "event" && \
echo "event 2"

done

如果您不想对事件执行任何命令,只需使用 -m 修饰符直接运行命令,这样就不会关闭:

inotifywait -e modify,create,delete,move -m -r /path/to/your/dir

【讨论】:

【参考方案6】:

不是 fanotify 最终应该提供这种能力吗? 引用LWN:

fanotify 有两种基本的‘模式’定向和全局。 [...] fanotify global 反而表明 它想要系统上的所有内容,然后单独标记 它不关心的 inode。

不过,我不知道它的最新状态是什么。

【讨论】:

根据对***.com/a/1847268/130352 的评论... fanotify 进入 2.6.36。【参考方案7】:

我有一个不同的建议,仅针对文件的更改,并记录历史更改

使用 git

cd /folder_to_monitor
git init
git add *
git commit -m "first snapshot"

所以在你做出改变之后

git diff

【讨论】:

在某些情况下它可能是一个有效的选项。不值得 -1【参考方案8】:

特别是对于您希望根据所见触发事件的大型或复杂监控任务,请查看Watchman A file watching service。这是一个简单的示例,用于在 CSS 文件更改时运行名为 minify-css 的工具:

$ watchman watch ~/src
$ watchman -- trigger ~/src buildme '*.css' -- minify-css

它进行全面的日志记录,可以有效地处理目录结构中重叠的多个手表,可以从命令行或通过 json 进行管理,等等。另见

Watchman – A File and Directory Watching Tool for Changes

它可以通过 Debian Sid 和 Ubuntu 20.04 获得,据我所知,它几乎已经两次进入 Fedora(1450590 和 1564720)。

【讨论】:

【参考方案9】:

我用它来快速浏览当前目录:

watch 'find . -printf "%T@ %Tc %p\n" | sort -nr | head '

【讨论】:

投反对票,因为 1)它没有回答问题(head 将削减绝大多数输出​​)和 2)考虑到 OP 的文件和目录的数量,这个答案甚至是不切实际的如果它是正确的,因为它会定期再次查看所有文件。 OP 一直在寻找更强大且开销更低的解决方案。

以上是关于如何在 Linux 中监视完整的目录树的更改?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Mac OS X 上监视目录中的更改?

如何监视 Windows 目录的更改?

如何解决“侦听错误:无法监视目录的更改”

FSNotify 在运行时添加监视目录

使用 perl (macos 和 linux) 监视文件的更改

监视或记录目录权限更改?