Monitoring file system changes in real time is essential for tasks ranging from automated build pipelines and log rotation to security auditing and configuration management. While polling-based approaches like watch or periodic find scans work, they are inefficient, resource-hungry, and introduce latency between the actual change and its detection.
The inotify subsystem in the Linux kernel provides an efficient, event-driven mechanism for monitoring file system events. The inotifywait and inotifywatch command-line utilities from the inotify-tools package expose this subsystem to shell scripts and terminal workflows, enabling you to react to file system changes the instant they occur.
What Is inotify and How Does It Work?
The inotify API is a Linux kernel subsystem that allows user-space applications to subscribe to file system events on specific files or directories. Unlike polling, which repeatedly checks the state of files at fixed intervals, inotify uses a push-based model — the kernel notifies your application the moment an event occurs.
This approach has several advantages:
- Zero CPU overhead between events — your process sleeps until the kernel wakes it with an event notification.
- Immediate detection — events are delivered within microseconds of the file system operation.
- Granular event types — you can subscribe to specific events such as creation, deletion, modification, access, attribute changes, and more.
The inotify-tools package provides two utilities that wrap the kernel inotify API for command-line use:
- inotifywait — waits for specific events and outputs them to standard output, making it ideal for scripting and automation.
- inotifywatch — collects file system event statistics over a period of time and presents them in a summary table.
Installing inotify-tools
The inotify-tools package is available in the default repositories of most major Linux distributions.
Debian, Ubuntu, and Derivatives
sudo apt update
sudo apt install inotify-tools
Fedora, RHEL, and CentOS Stream
sudo dnf install inotify-tools
Arch Linux and Manjaro
sudo pacman -S inotify-tools
openSUSE
sudo zypper install inotify-tools
Verify the installation by running:
inotifywait --help
Using inotifywait to Monitor File System Events
Basic Usage — Watching a Single File
The simplest use of inotifywait monitors a single file for any event:
inotifywait /path/to/file.txt
This command blocks until a file system event occurs on file.txt, then prints the event and exits. For example, if another process modifies the file, you might see:
/path/to/file.txt MODIFY
Watching a Directory
To monitor all events in a directory:
inotifywait /var/log/
This watches the directory itself for events such as new files being created or existing files being deleted. However, it does not watch the contents of files within the directory by default.
Recursive Monitoring
To monitor a directory and all its subdirectories recursively, use the -r flag:
inotifywait -r /home/user/projects/
This sets up inotify watches on every subdirectory within the specified path. New subdirectories created after monitoring begins are also automatically watched.
Continuous Monitoring with the Monitor Flag
By default, inotifywait exits after the first event. To monitor continuously, use the -m (monitor) flag:
inotifywait -m /var/log/syslog
The command now runs indefinitely, printing every event as it occurs:
/var/log/syslog MODIFY
/var/log/syslog MODIFY
/var/log/syslog ACCESS
Filtering Specific Events
The -e flag lets you subscribe to specific event types, reducing noise and focusing on the changes that matter to your workflow.
Available Event Types
- access — a file was read.
- modify — a file was written to.
- attrib — file metadata changed (permissions, timestamps, extended attributes).
- close_write — a file opened for writing was closed.
- close_nowrite — a file opened for reading only was closed.
- open — a file was opened.
- moved_to — a file was moved into the watched directory.
- moved_from — a file was moved out of the watched directory.
- create — a new file or directory was created.
- delete — a file or directory was deleted.
- delete_self — the watched file or directory itself was deleted.
- move_self — the watched file or directory itself was moved.
Monitoring Only File Modifications
inotifywait -m -e modify /etc/nginx/nginx.conf
Monitoring File Creation and Deletion
inotifywait -m -r -e create -e delete /var/www/html/
Monitoring Completed Write Operations
The close_write event is particularly useful for triggering actions after a file has been fully written, rather than reacting to each individual write operation:
inotifywait -m -e close_write /home/user/uploads/
Formatting Output for Scripting
The --format flag customises the output format, making it easier to parse in scripts. Available format specifiers include:
- %w — the watched path.
- %f — the filename (when watching a directory).
- %e — the event type(s).
- %T — the timestamp (requires
--timefmtto define the format).
Example: Timestamped Output
inotifywait -m -r -e modify -e create -e delete \
--timefmt '%Y-%m-%d %H:%M:%S' \
--format '%T %w%f %e' \
/var/log/
This produces output such as:
2026-11-05 09:15:32 /var/log/syslog MODIFY
2026-11-05 09:15:45 /var/log/auth.log MODIFY
2026-11-05 09:16:01 /var/log/cron.log CREATE
Practical Script Examples
Auto-Rebuild on Source Code Changes
This script watches a project’s source directory and triggers a build whenever a source file is saved:
#!/bin/bash
inotifywait -m -r -e close_write --include '\.(js|ts|css|html)$' /home/user/project/src/ |
while read -r directory event filename; do
echo "Change detected: $filename ($event)"
echo "Running build..."
cd /home/user/project/ && npm run build
echo "Build complete."
done
Automatic Log Compression
This script watches a log directory and compresses any new log files once they are fully written:
#!/bin/bash
inotifywait -m -e close_write --include '\.log$' /var/log/myapp/ |
while read -r directory event filename; do
echo "Compressing $directory$filename"
gzip "$directory$filename"
done
Security Audit — Monitoring Configuration File Changes
#!/bin/bash
inotifywait -m -r -e modify -e attrib -e delete \
--timefmt '%Y-%m-%d %H:%M:%S' \
--format '%T %w%f %e' \
/etc/ >> /var/log/config-audit.log 2>&1 &
This runs in the background and appends every configuration file change to an audit log with timestamps.
Using inotifywatch for Event Statistics
While inotifywait is designed for real-time event processing, inotifywatch collects event statistics over a defined period and presents a summary table.
Basic Usage
inotifywatch -t 60 -r /var/log/
This monitors /var/log/ recursively for 60 seconds, then prints a table showing how many of each event type occurred on each file:
total access modify close_write filename
152 89 52 11 /var/log/syslog
34 12 18 4 /var/log/auth.log
8 3 4 1 /var/log/kern.log
Use Cases for inotifywatch
- Identifying the busiest files in a directory tree during a specific time window.
- Baselining normal I/O activity before and after a deployment or configuration change.
- Detecting unexpected file access patterns that may indicate unauthorised activity.
Kernel Limits and Tuning
The inotify subsystem has kernel-level limits that control how many watches a single user can create. If you monitor large directory trees, you may encounter the error:
Failed to watch /path/to/dir; upper limit on inotify watches reached!
Checking Current Limits
cat /proc/sys/fs/inotify/max_user_watches
The default value is typically 8192 or 65536, depending on the distribution.
Increasing the Limit Temporarily
sudo sysctl fs.inotify.max_user_watches=524288
Making the Change Permanent
Add the following line to /etc/sysctl.conf or a file in /etc/sysctl.d/:
fs.inotify.max_user_watches=524288
Then reload the configuration:
sudo sysctl -p
Limitations of inotify
- Does not work across network file systems — inotify monitors the local VFS layer. Changes made to NFS, CIFS/SMB, or other network-mounted file systems by remote clients are not detected.
- No recursive watch inheritance on older kernels — while
inotifywait -rhandles this in user space, the kernel inotify API itself does not support recursive watches natively (unlike the newerfanotifyAPI). - Event queue overflow — if events arrive faster than your script can process them, the kernel event queue may overflow, and events will be lost. The
IN_Q_OVERFLOWevent signals this condition. - Watch descriptor limits — each watched directory or file consumes a watch descriptor. Monitoring very large directory trees requires tuning the kernel limits as described above.
Despite these limitations, inotifywait and inotifywatch remain the most efficient and widely used tools for file system event monitoring in Linux shell scripting. For workloads that exceed inotify’s capabilities, consider the fanotify API or dedicated file integrity monitoring tools such as AIDE or OSSEC.