1

With incrontab, I want to monitor a file and whenever it gets modified, I want to replace a string in it. But that will create an infinite loop, I guess. When I configure it with the following table:

/etc/file.md    IN_MODIFY   sed -i 's/Hello/Hi/g' $@

It works once, but never again. I don't see any error messages and the status of incrond remains fine, but I think the service is stuck in an infinite loop. If I restart it, it will work again one single time.

Is there a way to prevent such an infinite loop? Or is there another approach to my problem?

1
  • I think sed -i will rewrite the file regardless of it makes any changes (it can't know on the first line if the later lines will need changes). But you could add some other check to see if the file needs to be modified, before running sed. Perhaps something like grep -q Hello filename && sed -i 's/Hello/Hi/g' filename. Alternatively, create a script that runs sed on the file, putting the output in a temporary file somewhere where it's not monitored, and then only copies it in place if it's different from the original.
    – ilkkachu
    Jul 14, 2022 at 8:52

1 Answer 1

1

It turned out that I was not having an infinite loop, but I was experiencing this bug.

The service that modifies the file that I am monitoring, does not just modify the file, but deletes and recreates it. Through the deletion, incrond stops watching it, which can be determined when event IN_IGNORED is logged. That's why it always worked only once after a restart of incrond.

To not lose the watch on my file, I used the workaround also mentioned in the linked GitHub issue. Instead of monitoring the file directly, I monitor its parent directory. To not react to all other events in this directory I had to put my sed command into a script file and add a filter for the filename of my interest:

/etc    IN_CLOSE_WRITE  /home/user/myscript.sh $@ $#

With /home/user/myscript.sh:

#!/bin/bash
if [ "$2" == "file.md" ]; then
    sed -i 's/Hello/Hi/g' "$1/$2"
fi

I also changed IN_MODIFY to IN_CLOSE_WRITE, because IN_MODIFY seemed to trigger some ms too early for my needs.

Fortunately, the above table won't create a loop, because sed -i won't modify or write to the file, but replacing it (IN_MOVE_TO), so no IN_MODIFY or IN_CLOSE_WRITE.

1
  • Thank you, I was having the same problem and you were spot on with your explanation. Since I was calling scripts anyway I used the same solution with the only difference being that I flipped your conditional to make it an abort condition with an early exit. if [ "$2" != "buttons" ]; then exit 0; fi
    – keen
    Mar 12, 2023 at 21:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .