website/content/blog/command-when-file-in-directory-changes.md
2024-01-05 16:02:47 -05:00

2.3 KiB

title date draft tags math medium_enabled
Run a command when a file in a directory changes 2024-01-05T16:00:53-05:00 false
false 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.

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:

find $directory -type f | entr $command

An example can be running a build script if anything under the source folder changes:

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 on the internet is to wrap it in a while loop.

$ 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.

#!/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.

entr-dir src ./build.sh