Categories
shell workflow

flexible file watching: run any command on write

Run tests, compile code, and automate your job with this One Simple Trick.

intro

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.

In Ruby land, I’m likely to use Guard to run RSpec tests. In Javascript, I’m inclined to use Jest only for its test runner. In Scala, I’m going to use ~ to autorun tests in SBT. However, not all environments have simple tools like these languages to manage file watching, and you’ll likely find that you aren’t lucky enough to choose the build/test tools.

weak choices

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.

enter entr

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.

nodejs

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'

ruby

Run Rails migrations, then tests if they work

ls src/*/*Spec.rb | entr -rcs 'rails db:migrate && rspec'

shell

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'

ansible

Run a playbook whenever a yaml file is changed

ls **/*app .yaml | entr -c ansible-playbook ./playbook.yaml

fin

If you have unusual examples of automating your life with entr or file watchers comment so I can add them to my own workflow.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s