Run arbitrary commands when files change

overview | download 4.6 | man page


Rebuild project if sources change

$ ls | entr make

Rebuild project and run tests if the build was successful

$ ls | entr -s 'make && make test'

» ag and ack offer many advantages over utilities such as find(1) or ls(1) in that they recognize files by their contents and are smart enough to skip directories such as .git

Reducing Friction

entr adheres to the principle of separation of concerns, yet the reload (-r) option was added to solve a common use case that would otherwise require some careful scripting:

$ ls *.rb | entr -r ruby main.rb

This will,

  1. immediately start the server
  2. block until any of the listed files change
  3. terminate the background process
  4. wait for the server to exit before restarting

Other special-purpose flags were added because they reduce highly repetitive actions or reduce friction. One of the most repetitive actions was to clear the screen before running tests; hence the -c flag:

$ ls -d * | entr -c ./test.sh

The special /_ argument (somewhat analogous to $_ in Perl) provides a quick way to refer to the first file that changed. When a single file is listed this is a handy way to avoid typing a pathname twice:

$ ls *.sql | entr psql -f /_

Watching for New Files

The directory watch option (-d) was added to react to events when a new file is added to a directory. Since entr relies on standard input piped from other Unix tools, an external shell loop must be used to rescan the file system. One way to implement this feature would be to simply require the users to list directories, but entr will infer the directories if they aren't listed explicitly

$ while true; do
>   ls -d src/*.py | entr -d ./setup.py
> done

Other Implementation Details

Some architectural limitations are for good reasons, but it's not easy to see why a particular restriction applies.

First, the -r flag cannot be used with an interactive task:

  1. Closing STDIN on the child allows entr to accept keyboard input.
  2. If entr were to close it's own file descriptor to STDIN there is no reliable and immediate way to determine when the child has terminated in order to restore keyboard input.
  3. In restart mode signals need to propagate reliably, so we use a new process group. If the utility reads STDIN under this new process group, the kernel will suspend it. Finding your process in the T state is confusing, so we closes STDIN to raise an error instead.

Related Projects



Last updated on July 24, 2020
Send questions or comments to ericshane@eradman.com
Public keys for source: gpg | signify