I am trying to run a script which will watch different folder and files and if they change, execute a command. One of the folder paths accepts a dynamic variable which will change based on what is entered when running the script in the CLI, and the other one won't change.
Depending on the file path however, a different action needs to be taken.
#!/usr/bin/env bash
THEME=$1
while true;
do
echo "inside find"
find code/themes/$THEME/src -name '*.html' -o -name '*.ts' -o -name '*.scss' | entr -d rsync -avh code/themes/$THEME/* ./
find code/base/src -name '*.html' -o -name '*.ts' -o -name '*.scss' | entr -d rsync -avh code/base/* ./
done
What is happening when I run the script is that it only executes and places the watch on the first find (in the code pasted above's example, the dynamic path only).
Currently my problem is:
How do I get both to run at once? Or, how can I write it all in one line?
Also, I have never written scripts or used bash before, so if you have any advice on refactoring or are able to help with my problem, please be gentle with technical explanations.
My main goal is:
If your task is simply to make sure the downstream copies of the two (or 1 + number of themes) directories are always up to date, a cron
job which syncs them every n minutes might be the simplest and most robust solution. cron
has a per-minute granularity, though something like every five minutes may well be sufficient for your use case. rsync
by design does not copy files which are already up to date, so it should be reasonably quick to execute in the no-op case.
* * * * * bin/rsyncthemes
(This is once per minute; on Linux you can say */5
in the first field to run every 5 minutes, but this is not portable to all cron
dialects.) ... where rsyncthemes
contains something like
#!/bin/sh
# cron jobs always start in your home directory,
# but you want to put an absolute path here
# to run this in the directory where you want rsync to copy these files
cd somewhere
for dir in code/themes/one \
code/themes/other \
code/base
do
rsync -avh "$dir"/* ./
done
where obviously this needs to be marked executable (chmod a+x rsyncthemes
) and saved in the directory we specify in the cron
job (viz. bin
in your home directory).
If you are hellbent on using entr
to avoid running rsync
needlessly, though, I'm guessing you want something like
for dir in code/themes/one \
code/themes/other \
code/base
do
while true; do
find "$dir"/src -name '*.html' -o -name '*.ts' -o -name '*.scss' |
entr -d rsync -avh "$dir"/* ./
done & # <-- run each loop as a background job
done
In some more detail, we are running three while true
loops as background jobs, one for each of the directories enumerated in the for
loop. They are running in parallel with your interactive shell, and will stop running when you log out (unless you separately set them up to stay running with something like nohup
). The &
operator is what runs something in the background, and putting it after the while
loop's done
statement makes it apply to the entire loop.
I'm guessing you may need to use entr -n
in order for the jobs to run in the background.
The wildcard in the rsync
command gets expanded by the shell, so you might need to refactor this to not use a wildcard, or to evaluate the wildcard only after find
finishes, if you expect it to be possible for new files to appear in these directories occasionally. (Quoting the entire rsync
command and passing it with entr -s
should trivially accomplish this, if I'm reading the entr
man page correctly.)