如何监视一个完整的目录树在 Linux 中的变化?

如何监视 整个目录树对 Linux (Ext3文件系统)的更改?

目前,该目录在大约 3000个子目录中包含约 50万份文件,按三个目录级别组织。

这些文件大多是小文件(< 1kb,有些最大可达100kb)。这是一种队列,我需要知道文件何时被创建、删除或其内容在5-10秒内被修改。

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

如果 Linux 系统不能告诉我我需要什么: 也许有一个 保险丝项目可以模拟一个文件系统(在一个真实的文件系统上复制所有的文件访问) ,并单独记录所有的修改(不能很好的一个) ?

91484 次浏览

To my knowledge, there's no other way than recursively setting an inotify watch on each directory.

That said, you won't run out of file descriptors because inotify does not have to reserve an fd to watch a file or a directory (its predecessor, dnotify, did suffer from this limitation). inotify uses "watch descriptors" instead.

According to the documentation for inotifywatch, the default limit is 8192 watch descriptors, and you can increase it by writing the new value to /proc/sys/fs/inotify/max_user_watches.

Wasn't fanotify supposed to provide that capability eventually? Quoting LWN:

fanotify has two basic 'modes' directed and global. [...] fanotify global instead indicates that it wants everything on the system and then individually marks inodes that it doesn't care about.

I lost track what its latest status was, though.

I've done something similar using the inotifywait tool:

#!/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

This will setup recursive directory watches on the entire tree and allow you to execute a command when something changes. If you just want to view the changes, you can add the -m flag to put it into monitor mode.

$ inotifywait -m -r /path/to/your/directory

This command is enough to watch the directory recursively for all events such as access, open, create, delete ...

Use inotifywait from inotify-tools:

sudo apt install inotify-tools

Now create a script myscript.sh that includes hidden files and folders too:

#!/bin/bash
while true; do


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


done

Make the script executable with chmod +x myscript.sh

Run it with ./myscript.sh /folder/to/monitor

If you don't provide argument it will use the working directory by default.

Also, you can run several commands adding && \ at the end of the previous command to add the next one:

#!/bin/bash
while true; do


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


done

If you don't want to execute any command on events, just run the command directly with the -m modifier so doesn't close:

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

inotify is the best option when you have many subdirectories but if not I am used to using this command below:

watch -d find <<path>>

I have a different suggestion, only for changes in the files, and record history changes

use git

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

so after you make the changes

git diff

Especially for large or complex monitoring tasks in which you want to trigger events based on what you see, check out Watchman A file watching service. Here is a simple example to run a tool named minify-css whenever a CSS file is changed:

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

It does comprehensive logging, can efficiently handle multiple watches that overlap in a directory structure, can be administered from the command line or via json, and much more. See also

It is available via Debian Sid and Ubuntu 20.04, and has nearly made it in to Fedora twice from what I can see (1450590 and 1564720).

I use this to get a quick overview in the current directory:

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

I was facing the same problem, having a program that was creating some files (starting with a dot) whose content I wanted to manually inspect, but it automatically deleted them again soon after creation.

Using inotify in a loop without the monitor option didn't work for me, because it was too slow and missed events, so I came up with this script:

target="$1"


cd "$target"
mkdir backup/


inotifywait -e modify,create,delete --monitor -r --include "\..*" "$target" | \
while read line
do
echo "$line"
if [[ "$line" == "$target CREATE "* ]] || [[ "$line" == "$target MODIFY "* ]]
then
filename=${line#"$target CREATE "}
filename=${filename#"$target MODIFY "}
cp --verbose "$filename" backup/
fi
done