Search code examples
bashshellwhile-loopinotify

inotifywait ignore while loop


I am having trouble with using inotifywait properly.

My environment is CentOS 8 Stream with i7-9700

test.sh

#!/bin/bash

inotifywait -e modify ./test.txt |
while read dirname eventlist filename
do
  echo "Event catch!"
done

echo "I am doing next thing"

output in terminal(stdout)

[root@ceph examples]# sh test.sh
Setting up watches.
Watches established.
I am doing next thing

What I expect?

I expect that my script print the line, "Event catch!". As you can see, my bash script ignore all while loop block and just print "I am doing next thing".


Solution

  • The normal behavior of inotifywait is to exit after it has captured an event.

    If you want inotifywait to keep monitoring events, you have to use the -m option switch.

    Also in your script, you read 3 arguments from the output if inotifywait whereas only 2 might be returned if it has a single event. You may use the --format option to keep a predictable output format.

    #!/bin/sh
    
    inotifywait -m -e modify ./test.txt |
    while read -r filename eventlist
    do
      printf 'Event catch!\nfilename=%s, eventlist=%s\n' "$filename" "$eventlist"
    done
    
    printf %s\\n "I am doing next thing"
    

    If you want to exit inotifywait, you just kill the parent process from the pipe.

    Example:

    #!/bin/sh
    
    max_events=2
    inotifywait -m -e modify ./test.txt |
    while read -r filename eventlist
    do
      printf 'Event catch!\nfilename=%s, eventlist=%s\n' "$filename" "$eventlist"
      max_events=$((max_events - 1))
      [ 0 -eq "$max_events" ] && kill $$
    done
    
    printf %s\\n "I am doing next thing"
    

    And now with Bash arrays for events and reading a controlled format:

    #!/bin/bash
    
    max_events=2
    while
      # Reads file name
      read -r -d '' filename &&
      # and reads event list in an array
      read -r -a eventlist
    do
      declare -p filename eventlist
      printf 'Event catch!\nfilename! %s\neventlist: %s\n' "$filename" \
        "${eventlist[*]}"
      ((--max_events)) || break
    done < <(
      inotifywait --format '%w%0%e' --monitor --event MODIFY ./test.txt
    )
    
    printf %s\\n "I am doing next thing"