Skip to main content

Julia Evans

entr: rerun your build when files change

This is going to be a pretty quick post – I found out about entr relatively recently and I felt like WHY DID NOBODY TELL ME ABOUT THIS BEFORE?!?! So I’m telling you about it in case you’re in the same boat as I was.

There’s a great explanation of the tool with lots of examples on entr’s website.

The summary is in the headline: entr is a command line tool that lets you run an arbitrary command every time you change any of a set of specified files. You pass it the list of files to watch on stdin, like this:

git ls-files | entr bash my-build-script.sh

or

find . -name *.rs | entr cargo test

or whatever you want really.

quick feedback is amazing

Like possibly every single programmer in the universe, I find it Very Annoying to have to manually rerun my build / tests every time I make a change to my code.

A lot of tools (like hugo and flask) have a built in system to automatically rebuild when you change your files, which is great!

But often I have some hacked together custom build process that I wrote myself (like bash build.sh), and entr lets me have a magical build experience where I get instant feedback on whether my change fixed the weird bug with just one line of bash. Hooray!

restart a server (entr -r)

Okay, but what if you’re running a server, and the server needs to be restarted every time you change a file? entr’s got you – if you pass -r, then

git ls-files | entr -r python my-server.py

clear the screen (entr -c)

Another neat flag is -c, which lets you clear the screen before rerunning the command, so that you don’t get distracted/confused by the previous build’s output.

use it with git ls-files

Usually the set of files I want to track is about the same list of files I have in git, so git ls-files is a natural thing to pipe to entr.

I have a project right now where sometimes I have files that I’ve just created that aren’t in git just yet. So what if you want to include untracked files? These git command line arguments will do it (I got them from an email from a reader, thank you!):

git ls-files -cdmo --exclude-standard  | entr your-build-script

Someone emailed me and said they have a git-entr command that runs

git ls-files -cdmo --exclude-standard | entr -d "$@"

which I think is a great idea.

restart every time a new file is added: entr -d

The other problem with this git ls-files thing is that sometimes I add a new file, and of course it’s not in git yet. entr has a nice feature for this – if you pass -d, then if you add a new file in any of the directories entr is tracking, then it’ll exit.

I’m using this paired with a little while loop that will restart entr to include the new files, like this:

while true
do
{ git ls-files; git ls-files . --exclude-standard --others; } | entr -d your-build-script
done

how entr works on Linux: inotify

On Linux, entr works using inotify (a system for tracking filesystem events like file changes) – if you strace it, you’ll see an inotify_add_watch system call for each file you ask it to watch, like this:

inotify_add_watch(3, "static/stylesheets/screen.css", IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE_SELF|IN_MOVE_SELF) = 1152

that’s all!

I hope this helps a few people learn about entr!

A little bit of plain Javascript can do a lot Tell candidates what to expect from your job interviews