Skip to content

Comprehensive Guide to Monitoring File System Events with inotifywait

inotifywait is a C library and a set of command-line programs providing a simple interface to inotify.


Install inotify-tools on Gentoo Linux

emerge --ask inotify-tools

Additional Options

Monitor files that is edited/created/deleted/opened/closed in a dir

inotifywait -m -q -r \
  --format '%T % e %w%f' \
  --timefmt '%d/%m/%Y-%H:%M:%S%z' /mnt/usb/glftpd/ | \
   while IFS=' ' read -r time event file; do
    echo "file: $file"
  done

Monitor files that is edited/created/deleted/opened/closed in a dir (same as above but we avoid duplicates)

inotifywait -m -r \
  -e create,modify,delete,move \
  --format '%w%f|%e' \
  /tmp | \
awk -F'|' '
BEGIN { window=1 }  # seconds

{
    path=$1
    event=$2

    gsub(/,ISDIR/, "", event)
    event=tolower(event)

    if (event=="create") event="created"
    if (event=="modify") event="modified"
    if (event=="delete") event="deleted"

    key=path "|" event
    now=systime()

    # if same event on same file happened very recently, skip it
    if (last[key] && (now - last[key] <= window)) next

    last[key]=now
    print "File: " path " was " event
}'    

Monitor /tmp recursively for file create, modify, delete, and move events (Normalized Output)

inotifywait -m -r \
  -e create,modify,delete,move \
  --format 'File: %w%f was %e' \
  /tmp | \
awk -F' was ' '
{
    gsub(/,ISDIR/, "", $2)        # remove ISDIR
    $2 = tolower($2)              # lowercase event
    print $1 " was " $2
}'

Notify

while inotifywait -q -e modify filename >/dev/null; do
    echo "filename is changed"
    # do whatever else you need to do
done

Monitor dir every minute

inotifywatch -v -e access -e open -e create -e modify -t 60 -r

Close write

while inotifywait -e close_write myfile.py; do ./myfile.sh; done

Monitor a single directory (non-recursive)

inotifywait -q -m -e create /path/to/directory

Exclude specific files or directories

inotifywait -q -m -r --exclude '(^\.git|node_modules)' /path/to/directory

Only monitor specific file types

inotifywait -q -m -r --include '\.txt$' /path/to/directory"

Display events as they occur

inotifywait -m -r -e create /path/to/directory

Scripts

Run rsync by notify time¶

cwd=$(pwd)

inotifywait -mr \
    --timefmt '%d/%m/%y %H:%M' --format '%T %w %f' \
    -e close_write /tmp/test |
    while read -r date time dir file; do
        changed_abs=${dir}${file}
        changed_rel=${changed_abs#"$cwd"/}

        rsync --progress --relative -vrae 'ssh -p 22' "$changed_rel" \
            usernam@example.com:/backup/root/dir && \
            echo "At ${time} on ${date}, file $changed_abs was backed up via rsync" >&2
        done

If filename exist and inotiwait notice a change run script

inotifywait -e close_write,moved_to,create -m . |
while read -r directory events filename; do
  if [ "$filename" = "myfile.py" ]; then
    ./myfile.py
  fi
done

Monitor file and print last line when file is modified

inotifywait -r -e modify -m . \
    | while read -r directory events filename; do  
        tail -n1 $filename; 
      done

Print filename that was modified, created, or closed

inotifywait -r -e close_write,moved_to,create,modify -m $LOGDIR |
while read -r directory events filename; do
    echo $filename
done

Trigger a command each time a file is created in a directory (inotify)

inotifywait -mrq -e CREATE format %w%f /path/to/dir | 
    while read FILE; do 
        chmod g=u "$FILE";
    done

Immediately put execute permission on any file saved/created in $HOME/bin

inotifywait -mr -e CREATE $HOME/bin/ | 
    while read i; do 
        chmod +x $(echo "$i" | sed 's/ \S* //'); 
    done

Debug how files are being accessed by a process

inotifywait -m -r .

Print last filename that has been modified

inotifywait -m --exclude "[^j].$|[^s]$" /path -e create -e moved_to |
    while read dir action file; do
        echo "The file '$file' appeared in directory '$dir' via '$action'"
    done
httpd-logs

A short shell script to efficiently wait for httpd-related log messages and do something appropriate

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

Custom format

inotifywait -m -r --format '%:e %f' ~/test

Enforce file permissions

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

Block all brute-force attacks in realtime (IPv4/SSH)

inotifywait -r -q --format %w /var/log/auth.log \
    |grep -i "Failed pass" \
    |tail -n 1 \
    |grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}';
    iptables -I INPUT -i eth0 -s "$(cat /var/log/auth.log \
        |grep "authentication failure; l" \
        |awk -Frhost= '{print $2}' \
        |tail -n 1)" -j DROP

Notify when true

event=$(inotifywait --format '%e' /var/log) || exit
[ "$event" = "MODIFY" ] && echo 'file modified!' >&2
[ "$event" = "DELETE_SELF" ] && echo 'file deleted!' >&2

Monitor dir and if file extension match, remove metadata (example)"

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        if [[ "$file" =~ .*xml$ ]]; then # Does the file end with .xml?
            echo "xml file" # If so, do your thing here!
        fi
done

Print filename with full path for all newly created files

inotifywait -q -m -r -e create /home/wuseman/emagnet/websites/nohide.space/ |
  while read -r directory event filename; do
    if [[ $event == "CREATE" ]]; then
      echo "File created: $directory$filename"
    fi
  done

Print filename for all modified files

inotifywait -q -m -r -e modify /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "MODIFY" ]]; then
      echo "File modified: $filename"
    fi
  done

Execute a command on file creation

inotifywait -q -m -r -e create /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "CREATE" ]]; then
      # Replace the following line with your desired command
      command_to_execute "$filename"
    fi
  done

Print filename and timestamp for all modified files

inotifywait -q -m -r -e modify /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "MODIFY" ]]; then
      echo "File modified: $filename"
      echo "Timestamp: $(date +"%Y-%m-%d %H:%M:%S")"
    fi
  done

Perform an action on modified files

inotifywait -q -m -r -e modify /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "MODIFY" ]]; then
      # Replace the following line with your desired action
      echo "File modified: $filename"
      # Perform your action here
    fi
  done

Track specific file extensions

inotifywait -q -m -r -e modify --include '\.(txt|csv)$' /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "MODIFY" ]]; then
      echo "File modified: $filename"
    fi
  done

Print filename and size for all modified files

inotifywait -q -m -r -e modify --format '%f %s' /path/to/directory |
  while read -r filename size; do
    echo "File modified: $filename"
    echo "Size: $size bytes"
  done

Monitor file deletions

inotifywait -q -m -r -e delete /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "DELETE" ]]; then
      echo "File deleted: $filename"
    fi
  done

Track directory modifications

inotifywait -q -m -r -e modify --format '%w%f' /path/to/directory |
  while read -r modified_path; do
    echo "Directory modified: $modified_path"
  done

Exclude specific file types

inotifywait -q -m -r -e modify --exclude '\.(jpg|png)$' /path/to/directory |
  while read -r directory event filename; do
    if [[ $event == "MODIFY" ]]; then
      echo "File modified: $filename"
    fi
  done

Print filename and event type

inotifywait -q -m -r -e modify --format '%w%f %e' /path/to/directory |
  while read -r modified_path event_type; do
    echo "File modified: $modified_path"
    echo "Event type: $event_type"
  done

Print detailed information using JSON format

inotifywait -q -m -r -e modify --format '{"path": "%w%f", "event": "%e"}' /path/to/directory |
  while read -r json_data; do
    echo "Received event:"
    echo "$json_data"
    # Process the JSON data as needed
  done

Custom output format with additional information

inotifywait -q -m -r -e modify --format 'File: %w%f, Event: %e, Timestamp: %T' /path/to/directory |
  while read -r output; do
    echo "$output"
  done

To watch for created files and delete them if they are not of type .xt, you can use the following script

inotifywait -q -m -r -e create --format '%w%f' /path/to/directory |
while read -r created_file; do
  if [[ ! $created_file =~ \.xt$ ]]; then
    echo "Deleting file: $created_file"
    rm "$created_file"
  fi
done

Watch multiple events

This command monitors the specified directory (/path/to/directory) for multiple events (create, modify, and delete). The -e option is used to specify the events to watch, separated by commas.

inotifywait -q -m -r -e create,modify,delete /path/to/directory

Colorize entire output line based on file event type

Screenshot

inotifywait -m -r \
  -e create,modify,delete,move \
  --format '%w%f|%e' \
  /tmp | \
awk -F'|' '
BEGIN {
  # ANSI colors
  RED   = "\033[1;31m"
  GRN   = "\033[1;92m"   # bright/light green
  YEL   = "\033[1;93m"   # bright/light yellow (often looks orange-ish)
  RESET = "\033[0m"
}
{
  event=$2
  gsub(/,ISDIR/, "", event)
  event=tolower(event)

  if (event=="create") event="created"
  if (event=="modify") event="modified"
  if (event=="delete") event="deleted"

  msg="File: " $1 " was " event
  if (msg == last) next
  last=msg

  # choose color by event
  color=RESET
  if (event=="deleted")  color=RED
  else if (event=="created")  color=GRN
  else if (event=="modified") color=YEL

  print color msg RESET
}'

Colorize event keywords while preserving neutral output

Screenshot

inotifywait -m -r \
  -e create,modify,delete,move \
  --format '%w%f|%e' \
  /tmp | \
awk -F'|' '
BEGIN {
  # Colors
  WHT   = "\033[1;97m"   # bright white
  RED   = "\033[1;31m"
  GRN   = "\033[1;92m"
  YEL   = "\033[1;93m"
  RESET = "\033[0m"
}
{
  event=$2
  gsub(/,ISDIR/, "", event)
  event=tolower(event)

  if (event=="create") event="created"
  if (event=="modify") event="modified"
  if (event=="delete") event="deleted"

  prefix = WHT "File:" RESET
  msg = prefix " " $1 " was "

  if (msg event == last) next
  last = msg event

  colored_event = event
  if (event=="deleted")
      colored_event = RED event RESET
  else if (event=="created")
      colored_event = GRN event RESET
  else if (event=="modified")
      colored_event = YEL event RESET

  print msg colored_event
}'