I spend most of my workday in a shell. Most of that time is spent running the same 5ish commands across 30+ repositories encompassing vastly different toolchains. One day I’ll be working in Java in Intellij, the next Golang in Vim, the next Typescript direct on some cloud provider.
Each of these environments has its own, highly opinionated toolchains for development, TDD or deployment.
Take one problem. Running tests whenever a file is written.
I’ve dug around native solutions and other tools, but you’ll quickly find yourself writing large custom scripts to do what seems like an easy task.
Inotify is installed on many Linux machines but controlling whether a process should wait for completion, exit early, or prevent multiple invocations overlapping will require a custom solution for each type of process you run. You may also find yourself exhausting the number of filewatchers very easily for no easily fixable reason in larger codebases.
Entr is a command-line utility that vastly simplifies the task of performing arbitrary actions when writing a file.
Using entr is incredibly simple. Echo the name of a file, pipe it to entr and give it a command to run. You can see me running the simplest possible command in a NodeJS environment below.
Entr is simple but massively flexible. It can be used to replace an entire suite of third party tools. Here are some of my favourite usecases.
Replace nodemon. Restart a web server anytime a file changes.
-r will kill and rerun the command when triggered.
ls src/**/*.js | entr -r npm run start
Replace mocha watch with a more reliable system that only runs when a test file is changed.
-c will clear the screen before each run.
ls src/**/*.test.js | entr -rc yarn test
Replace jest individual test runner.
/_ is a placeholder that will be replaced with the last file changed.
ls src/**/*.test.js | entr -c npm run test /_
Invoke a serverless function whenever you change its request body json. Adding
-s will invoke the passed string argument with
$SHELL meaning you can use any bash-isms you’d like.
echo request.json | entr -sc 'npm run compile && serverless invoke local -f myFunc -p ./request.json'
Run Rails migrations, then tests if they work
ls src/*/*Spec.rb | entr -rcs 'rails db:migrate && rspec'
Run a shell command any time it changes. Use this to develop scripts and see line by line debug info.
echo myScript.sh | entr -cs 'bash -x myScript.sh'
Run a playbook whenever a yaml file is changed
ls **/*app .yaml | entr -c ansible-playbook ./playbook.yaml
If you have unusual examples of automating your life with entr or file watchers comment so I can add them to my own workflow.