Skip to content

Instantly share code, notes, and snippets.

@mk-pmb
Created November 7, 2025 04:53
Show Gist options
  • Select an option

  • Save mk-pmb/be2ac9bd98851fe4fe82a557c95a60c1 to your computer and use it in GitHub Desktop.

Select an option

Save mk-pmb/be2ac9bd98851fe4fe82a557c95a60c1 to your computer and use it in GitHub Desktop.
#!/bin/bash
# -*- coding: utf-8, tab-width: 2 -*-
function file_repl () {
export LANG{,UAGE}=en_US.UTF-8 # make error messages search engine-friendly
local SELFPATH="$(readlink -m -- "$BASH_SOURCE"/..)"
cd -- "$SELFPATH" || return $?
local BFN="$FUNCNAME.$(printf '%(%y%m%d-%H%M%S)T' -1)-$$"
local DEFAULT_SCAN_INTV=10
local DELAY=2 # How long to give job files to settle on disk.
exec </dev/null
>>"$BFN".pid
sleep "$DELAY" || true
local REN='mv --no-clobber --no-target-directory --'
local INTV= JOB= FEXT=
while [ -f "$BFN".pid ]; do
echo "D: $FUNCNAME[$$] scan $BFN.*"
for JOB in "$BFN".*.{rc,sh}; do
[ -f "$JOB" ] || continue
echo "D: $FUNCNAME[$$] $JOB"
FEXT="${JOB##*.}"
JOB="${JOB%.*}"
sleep "$DELAY" || true
$REN "$JOB".{$FEXT,wip} || continue
case "$FEXT" in
rc ) source -- "$JOB".wip &>"$JOB".log; job_done $?;;
sh ) one_job & disown $!;;
esac
done
[ "$INTV" != quit ] || break
[ "${INTV:-0}" -ge 1 ] || INTV="$DEFAULT_SCAN_INTV"
echo "D: $FUNCNAME[$$] wait $INTV"
sleep "$INTV"s || return $?
done
rm -- "$BFN.pid" 2>/dev/null
echo "D: $FUNCNAME[$$] quit"
}
function one_job () {
echo "D: $FUNCNAME[$$] $*"
echo "<< $FUNCNAME[$$] >>" >>"$JOB".log
timeout --signal=TERM --kill-after=1m 1h bash "$JOB".wip &>>"$JOB".log
job_done $?
}
function job_done () {
local RV=$1
printf '\n%(%T %F)T rv=%s\n' -1 "$RV" >>"$JOB".log
local FEXT='done'
[ "$RV" == 0 ] || FEXT="err-$RV"
$REN "$JOB".{wip,"$FEXT"}
}
# Fork off so we can run this from an NTFS network share without having
# the parent shell holding a lock on the file.
file_repl "$@" & disown $!; exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment