inotifywait(1)

πŸ’– inotifywait(1) + fsnotifywait(1) πŸ’–

okay so this is the General Commands Manual page for two iconic little tools, and they are literally here to make your shell scripts feel main character energy. no cap.


🌸 NAME 🌸

inotifywait, fsnotifywait β€” wait for changes to files using inotify or fanotify. that's the whole vibe: you point them at files, they wait, and they tell you what happened. 🫢


✨ SYNOPSIS ✨

inotifywait [-hcmrPqIFMS] [-e <event> ] [-t <seconds> ] [--format <fmt>
] [--timefmt <fmt> ] <file> [ ... ]

fsnotifywait [-hcmrPqIFS] [-e <event> ] [-t <seconds> ] [--format <fmt>
] [--timefmt <fmt> ] <file> [ ... ]

πŸ¦‹ DESCRIPTION πŸ¦‹

inotifywait is the efficient wait-for-changes bestie, and by default it uses Linux's inotify(7) interface. it is suitable for waiting for changes to files from shell scripts, which is honestly its whole moment. it can either exit once an event occurs, or continually execute and output events as they occur. pick your vibe.

fsnotifywait is similar to inotifywait, but it uses Linux's fanotify(7) interface by default. if you explicitly specify it, it uses the inotify(7) interface instead. slay. πŸ’…


πŸ’… OUTPUT πŸ’…

okay so both tools output diagnostic information on standard error and event information on standard output. the event output can be configured, but by default it consists of lines of the following form:

watched_filename EVENT_NAMES event_filename
  • watched_filename β€” is the name of the file on which the event occurred. if the file is a directory, a trailing slash is output. yes, the slash is part of the look. ✨
  • EVENT_NAMES β€” are the names of the inotify events which occurred, separated by commas.
  • event_filename β€” is output only when the event occurred on a directory, and in this case the name of the file within the directory which caused this event is output.

by default, any special characters in filenames are not escaped in any way. this can make the output of inotifywait difficult to parse in awk scripts or similar. the --csv and --format options will be helpful in this case. fr fr.


πŸŽ€ OPTIONS πŸŽ€

here is the whole menu, bestie. every flag, every detail, no skips. πŸ“

  • -h, --help β€” output some helpful usage information. it's giving "help me help you". πŸ’–
  • @<file> β€” when watching a directory tree recursively, exclude the specified file from being watched. the file must be specified with a relative or absolute path according to whether a relative or absolute path is given for watched directories. if a specific path is explicitly both included and excluded, it will always be watched.
note: if you need to watch a directory or file whose name starts with @, give the absolute path. iykyk.
  • --fromfile <file> β€” read filenames to watch or exclude from a file, one filename per line. if filenames begin with @ they are excluded as described above. if <file> is -, filenames are read from standard input. use this option if you need to watch too many files to pass in as command line arguments. iconic for the "too many files" era. πŸ“
  • -m, --monitor β€” instead of exiting after receiving a single event, execute indefinitely. the default behaviour is to exit after the first event occurs. so -m is the "stay a while" button. 🫢
  • -d, --daemon β€” same as --monitor, except run in the background logging events to a file that must be specified by --outfile. implies --syslog. background bestie behavior. πŸ’…
  • -o, --outfile <file> β€” output events to <file> rather than stdout. take the party to a file.
  • -s, --syslog β€” output errors to syslog(3) system log module rather than stderr.
  • -P, --no-dereference β€” do not follow symlinks. respect the link's boundaries, periodt.
  • -r, --recursive β€” watch all subdirectories of any directories passed as arguments. watches will be set up recursively to an unlimited depth. symbolic links are not traversed. newly created subdirectories will also be watched.
⚠️ warning: if you use this option while watching the root directory of a large tree, it may take quite a while until all inotify watches are established, and events will not be received in this time. also, since one inotify watch will be established per subdirectory, it is possible that the maximum amount of inotify watches per user will be reached. the default maximum is 8192; it can be increased by writing to /proc/sys/fs/inotify/max_user_watches. so maybe don't rawdog -r on / unless you're ready. 😭
  • -q, --quiet β€” if specified once, the program will be less verbose. specifically, it will not state when it has completed establishing all inotify watches. if specified twice, the program will output nothing at all, except in the case of fatal errors. two -qs is the "don't perceive me" setting. πŸ™ˆ
  • --exclude <pattern> β€” do not process any events for the subset of files whose filenames match the specified POSIX regular expression, case sensitive. filter them out, bestie.
  • --excludei <pattern> β€” do not process any events for the subset of files whose filenames match the specified POSIX regular expression, case insensitive. same energy, lowercase-friendly.
  • --include <pattern> β€” process events only for the subset of files whose filenames match the specified POSIX regular expression, case sensitive. when used with --recursive, events will still be generated for matching files inside newly created directories, even if the directory names themselves do not match the pattern. that's the little exception, don't forget it. ✨
  • --includei <pattern> β€” process events only for the subset of files whose filenames match the specified POSIX regular expression, case insensitive.
  • -t <seconds>, --timeout <seconds> β€” exit if an appropriate event has not occurred within <seconds> seconds. if <seconds> is zero (the default), wait indefinitely for an event. so -t 0 is the "i have all the time in the world" setting. ⏳
  • -e <event>, --event <event> β€” listen for specific event(s) only. the events which can be listened for are listed in the EVENTS section. this option can be specified more than once. if omitted, all events are listened for. picky listener era. πŸ‘‘
  • -c, --csv β€” output in CSV (comma-separated values) format. this is useful when filenames may contain spaces, since in this case it is not safe to simply split the output at each space character. csv is the safe-space for spaces. πŸŽ€
  • --timefmt <fmt> β€” set a time format string as accepted by strftime(3) for use with the %T conversion in the --format option.
  • --no-newline β€” don't print newline symbol after user-specified format in the --format option. no extra line break, no extra drama.
  • --format <fmt> β€” output in a user-specified format, using printf-like syntax. the event strings output are limited to around 4000 characters and will be truncated to this length. the following conversions are supported:
    • %w β€” this will be replaced with the name of the Watched file on which an event occurred. when an event occurs within a Watched directory or when watching with fanotify, this will be replaced with the name of the Directory in which the event occurred.
    • %f β€” when an event occurs within a Watched directory or when watching with fanotify, this will be replaced with the name of the File which caused the event to occur. otherwise, this will be replaced with an empty string.
    • %e β€” replaced with the Event(s) which occurred, comma-separated.
    • %Xe β€” replaced with the Event(s) which occurred, separated by whichever character is in the place of X.
    • %T β€” replaced with the current Time in the format specified by the --timefmt option, which should be a format string suitable for passing to strftime(3).
    • %0 β€” replaced with NUL.
    • %n β€” replaced with Line Feed.
  • -I, --inotify β€” watch using inotify (default for inotifywait).
  • -F, --fanotify β€” watch using fanotify (default for fsnotifywait). fanotify support for reporting events with inotify compatible information was added in kernel v5.9. with older kernels the command will fail. as of kernel v5.12, fanotify requires admin privileges. so yeah, check your kernel before you get too excited. πŸ’€
  • -S, --filesystem β€” watch entire filesystem of any directories passed as arguments using fanotify. whole filesystem energy. 🌈
  • -M, --mount β€” watch entire mount of any directories passed as arguments using fanotify. mount-wide main character moment. ⭐

🌈 EXIT STATUS 🌈

  • 0 β€” the program executed successfully, and an event occurred which was being listened for. slay. πŸ’–
  • 1 β€” an error occurred in execution of the program, or an event occurred which was not being listened for. the latter generally occurs if something happens which forcibly removes the inotify watch, such as a watched file being deleted or the filesystem containing a watched file being unmounted. not the vibe. 😭
  • 2 β€” the -t option was used and an event did not occur in the specified interval of time. timeout bestie says bye. ⏰

✨ EVENTS ✨

Okay bestie, these are the events you can pass to -e. Each one is a little notification about what happened to your watched file (or a file chilling inside a watched directory). Pick your faves πŸ’…

  • access β€” a watched file, or a file inside a watched directory, got read from. Someone looked at it πŸ‘€
  • modify β€” a watched file, or a file inside a watched directory, got written to. Content changed, no cap.
  • attrib β€” the metadata of a watched file (or a file inside a watched directory) changed. That's timestamps, file permissions, extended attributes, all of that. The file itself didn't change but its whole vibe did πŸŽ€
  • close_write β€” a watched file (or one inside a watched directory) was closed after being opened in writable mode. Important: this does not necessarily mean anything was actually written to it. Opened for writing and closed, that's it 🫢
  • close_nowrite β€” a watched file (or one inside a watched directory) was closed after being opened in read-only mode.
  • close β€” a watched file (or one inside a watched directory) was closed, no matter how it was opened. Sneaky detail: this is actually just implemented by listening for both close_write and close_nowrite, so every close event you get comes out as one of those two β€” never as CLOSE. Not me exposing the implementation 😭
  • open β€” a watched file, or a file inside a watched directory, was opened.
  • moved_to β€” a file or directory got moved into a watched directory. This fires even if the file was just moved from that same directory and right back into it. Yes, really. Same-directory shuffle still counts ✨
  • moved_from β€” a file or directory got moved from a watched directory. Also fires even if it's just a move from and to the same directory.
  • move β€” a file or directory was moved from or to a watched directory. Same deal as close: it's implemented by listening for both moved_to and moved_from, so every move event comes out as one or both of those β€” never as MOVE. Periodt πŸ’…
  • move_self β€” the watched file or directory itself was moved. After this event, that file or directory is no longer being watched. It's gone from the watchlist, bestie πŸ’€
  • create β€” a file or directory was created inside a watched directory.
  • delete β€” a file or directory inside a watched directory was deleted.
  • delete_self β€” the watched file or directory itself was deleted. After this event, it's no longer being watched. Heads up: this event can fire even if you didn't explicitly ask to listen for it. Surprise notification πŸ™ˆ
  • unmount β€” the filesystem that the watched file or directory lives on got unmounted. After this event, it's no longer being watched. Same caveat: this one can occur even if you never explicitly listened for it. Rude but true 😭

🌸 EXAMPLES 🌸

Example 1

Running inotifywait at the command line to wait for any file in the test directory to be accessed. After you run inotifywait, somebody runs cat test/foo in a separate console.

% inotifywait test
Setting up watches.
Watches established.
test/ ACCESS foo

Look at that. ACCESS, filename foo, directory test/. Slay 🌈

Example 2

A short shell script that efficiently waits for httpd-related log messages and then does something appropriate about it. Iconic little loop 🧚

#!/bin/sh
while ! inotifywait -e modify /var/log/messages; do
  if tail -n1 /var/log/messages | grep httpd; then
    kdialog --msgbox "Apache needs love!"
  fi
done

Apache needs love. We've all been there πŸ’–

Example 3

Here a custom output format is used to watch ~/test. Meanwhile, in another console, someone runs touch ~/test/badfile; touch ~/test/goodfile; rm ~/test/badfile.

% inotifywait -m -r --format '%:e %f' ~/test
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
CREATE badfile
OPEN badfile
ATTRIB badfile
CLOSE_WRITE:CLOSE badfile
CREATE goodfile
OPEN goodfile
ATTRIB goodfile
CLOSE_WRITE:CLOSE goodfile
DELETE badfile

See how the colon separates multiple events on one line? CLOSE_WRITE:CLOSE β€” two events, one file, one line. That's the %:e doing its thing ✨

Example 4

Enforce file permissions in the directory ~/test:

inotifywait -qmr -e 'moved_to,create' --format '%w%f%0' --no-newline ~/test |\
    while IFS= read -r -d '' file
    do
       chmod -v a+rX "$file"
    done

The %0 gives you a NUL byte, and read -r -d '' splits on it, so filenames with spaces stay intact. Big brain energy 🧠✨


πŸ’€ CAVEATS πŸ’€

Bestie, listen. When you use inotifywait, the filename it outputs is not guaranteed to be up to date after a move, because what's actually being monitored is the inode. Also, none of the observed operations are guaranteed to have been performed on the filename that inotifywait was told to monitor, in cases where the file is known by several names in the filesystem. Multiple names, one inode, chaos πŸ™ˆ

So like... it's watching the thing, not necessarily the name you typed. Keep that in mind, fr fr.

😭 BUGS 😭

There are race conditions in the recursive directory watching code, which can cause events to be missed if they happen in a directory immediately after that directory is created. This is probably not fixable. Not me, not you, not anybody. It's just how it is πŸ’€

It is also assumed that the inotify event queue will never overflow. Yeah. That's the assumption. We're just vibing with it 🫠


πŸ‘‘ AUTHORS πŸ‘‘

inotifywait was started by Rohan McGovern, and is currently maintained by Eric Curtin and Radu Voicilas.

https://www.openhub.net/p/inotify-tools/contributors/summary gives you a more complete list of contributors. Shoutout to everybody in the group chat 🫢

inotifywait is part of inotify-tools. The inotify-tools website lives at:

https://github.com/inotify-tools/inotify-tools/wiki


πŸ¦‹ SEE ALSO πŸ¦‹


That's the whole page, bestie! This beauty is inotifywait 4.26.0, dated 2026-10-07 β€” yes, the future is now, and the manual page is still called inotifywait(1). Go watch some directories, you absolute icon πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from