0

After some googling, I found the entr utility to run a command on a file update. I can get it working, but unfortunately, I'm unable to exit from it.

The literature about it isn't much and quite vague for me. I'd need a behaviour, like

  • detect file change
  • run my command (setting a VAR in the caller script)
  • exit

But not sure how to achive this. Calling entr seems to be an infinite loop, it's running endlessly.

It's rather strange I couldn't find any similar usecases. (https://github.com/eradman/entr)

Should I start playing with the inotifywait from inotify-tools package?

Giacomo1968
  • 58,727
gamb1t9
  • 11

2 Answers2

1

Thanks @Kamil Maciorowski for the detailed answer.

Since I'm already dealing with a temp file, I wouldn't bother creating another temp file for entr's subprocess to store it's value.

Altough entr seems to be a cool little tool, I went with inotifywait:

inotifywait -q -e close_write $buff_file_path |
while read -r filename event; do
    :
done
result=$(cat $buff_file_path)

This will exit when an event occures. I'm basically just monitoring the file, and only reading it when it updated.

My initial description of the problem / desired result is a bit shady, I'll have to work on writing decent questions.

Credit goes to the kind people in this thread.

gamb1t9
  • 11
0

Formal note

Your explicit question is:

Should I start playing with the inotifywait from inotify-tools package?

I cannot answer this. Answers to "should I?" are usually opinion-based anyway. I think the implicit question is "how can I exit from entr inside a script?". This is the question answered below.


Solution

The following command:

entr -p sh -c 'kill -s INT "$PPID"; actual command(s)'

will (upon being triggered) make entr spawn a shell that will kill its parent (i.e. entr) and then execute actual command(s).


Notes

  • Without -p entr would execute sh right away and be killed right away. You need -p. From man 1 entr:

    -p    Postpone the first execution of the utility until a file is modified.

  • entr takes a command to be executed (executable + arguments) as its own separate arguments. A syntax like:

    entr echo "$var"
    

    is totally fine. However for sh -c you pass shell code, a string that will be interpreted by the shell. Our actual command(s) will be parsed by the shell. If you need the outer shell to expand anything and pass to the inner shell, do not do this:

    entr -p sh -c 'kill -s INT "$PPID";'" echo $var"

    nor anything like it. To do it safely, make the shell code (the option-argument for sh -c) static and use positional arguments to pass variable values. Example:

    entr -p sh -c 'kill -s INT "$PPID"; echo "$1"' sh "$var"
    

    Here, even if $var expands to ; rogue code, '; rogue code, '$(rogue code) or anything else, it won't be able to break the actual shell code.

    (Compare "never embed {} in the shell code", it's basically the same issue.)

  • Your goal is "setting a VAR in the caller script". Without a debugger only the shell interpreting the script can change its its own variables. A command run under entr cannot do this. You can capture its output or make it write to a file and then let the shell read the file. See answers to this question: Capture specific environment variable from Linux sub-shell.