diff --git a/content/blog/command-when-file-in-directory-changes.md b/content/blog/command-when-file-in-directory-changes.md new file mode 100644 index 0000000..04a521c --- /dev/null +++ b/content/blog/command-when-file-in-directory-changes.md @@ -0,0 +1,87 @@ +--- +title: "Run a command when a file in a directory changes" +date: 2024-01-05T16:00:53-05:00 +draft: false +tags: [] +math: false +medium_enabled: false +--- + +When editing code or adding content to a HTML file for a website, it can be very useful to see the changes right away after you save the file. We'll show a lightweight way of accomplishing this task with `entr` and a bit of bash scripting. + +First if you don't already have it, install `entr`. + +```bash +sudo dnf install entr +``` + +This terminal application works by monitoring files passed within standard in. Therefore, to run a `$command` if any file under some `$directory` changes run the following: + +```bash +find $directory -type f | entr $command +``` + +An example can be running a build script if anything under the source folder changes: + +```bash +find src -type f | entr ./build.sh +``` + +Now this doesn't capture files that get added to the directory. To do this, we need to get `entr` to monitor the parent folder for any changes. We can do this with the `-d` flag. + +From the man page: + +> **-d** Track the directories of regular files provided as input and exit if +> a new file is added. + +Since `entr` exits when a file gets added with this flag, the [common solution](https://superuser.com/a/665208) on the internet is to wrap it in a `while` loop. + +```bash +$ while sleep 0.1 ; do find $directory -type f | entr -d $command ; done +``` + +This solution works great as a one-liner, but it doesn't let me CTRL-C out when I'm finished. Therefore, I wrote a shell script that incorporates this solution while also adding a `trap`. + +```bash +#!/bin/bash + +set -o nounset +set -o pipefail + +show_usage() { + echo "Usage: entr-dir [dir] [command]" + exit 1 +} + +# Check argument count +if [ "$#" -lt 2 ]; then + show_usage +fi + +# Make sure that the command entr exists +if ! command -v entr > /dev/null ; then + echo "entr not found. Exiting..." + exit 1 +fi + +DIR="$1"; shift + +if [[ ! -d "$DIR" ]]; then + echo "First argument must be a directory. Exiting..." + exit 1 +fi + +# Allow for CTRL-C to exit script +trap "exit 0;" SIGINT + +while sleep 0.1; do + find "$DIR" -type f | entr -d "$@" +done +``` + +I plopped this in `~/.local/bin/entr-dir`, gave it the `+x` permission, and now I can easily monitor and build projects when files get changed/added/deleted. + +```bash +entr-dir src ./build.sh +``` +