Last active
July 26, 2025 13:25
-
-
Save kawanet/2eadbbf03f3619a28bb7cd6f36985f8d to your computer and use it in GitHub Desktop.
Loop-run systemd’s ExecStart command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
#--- | |
## @file exec-service.sh | |
## @brief Loop-run systemd’s ExecStart command | |
## @see https://gist.github.com/kawanet/2eadbbf03f3619a28bb7cd6f36985f8d | |
## @author Yusuke Kawasaki | |
## @license MIT | |
#--- | |
die () { | |
echo "$1" >&2 | |
exit 1 | |
} | |
warn () { | |
echo "$1" >&2 | |
} | |
prompt () { | |
local cmd=("$@") | |
if [ -z "$PROMPT" ]; then | |
local user=${USER:-$(whoami)} | |
if [ "$user" = "root" ]; then | |
PROMPT="[$user]#" | |
else | |
PROMPT="[$user]$" | |
fi | |
fi | |
echo "$PROMPT ${cmd[@]}" >&2 | |
} | |
if command -v perl > /dev/null 2>&1; then | |
strip_nl() { perl -pe 's/\\\n//g' < "$1"; } | |
else | |
strip_nl() { sed ':a;N;$!ba;s/\\\n//g' < "$1"; } | |
fi | |
getconf () { | |
local unit="$1" | |
local key="$2" | |
local row=$(strip_nl "$unit" | grep "^$key") | |
local value="${row#*=}" | |
echo $value | |
} | |
start_unit () { | |
unit="$1" | |
WorkingDirectory=$(getconf "$unit" WorkingDirectory) | |
Environment=$(getconf "$unit" Environment) | |
ExecStartPre=$(getconf "$unit" ExecStartPre) | |
ExecStart=$(getconf "$unit" ExecStart) | |
[ -n "$ExecStart" ] || die "Error: ExecStart is required in the service file: $unit" | |
if [ -n "$WorkingDirectory" ]; then | |
cd "$WorkingDirectory" || die "Error: Failed to cd to '$WorkingDirectory'." | |
fi | |
if [ -n "$ExecStartPre" ]; then | |
prompt $ExecStartPre | |
env $Environment $ExecStartPre || die "Error: ExecStartPre failed with code $?" | |
fi | |
prompt $ExecStart | |
env $Environment $ExecStart & | |
} | |
forward() { | |
sig="$1" | |
warn "SIGNAL: $sig" | |
for pid in $(pgrep -P $$); do | |
kill -s "$sig" "$pid" 2>/dev/null | |
done | |
} | |
[ "$#" -gt 0 ] || die "Usage: $0 /etc/systemd/system/xxxx.service" | |
trap 'forward HUP' HUP | |
trap 'forward USR1' USR1 | |
trap 'forward USR2' USR2 | |
trap 'forward TERM; sleep 1; exit 0' TERM | |
trap 'forward INT; sleep 1; exit 0' INT | |
args=("$@") | |
pids=() | |
delay=1 | |
start_all() { | |
local len=${#args[@]} | |
for (( idx=0; idx<len; idx++ )); do | |
local pid=${pids[idx]} | |
if [ -z "$pid" ] || ! kill -0 "$pid" 2>/dev/null; then | |
start_unit "${args[idx]}" | |
pids[$idx]=$! | |
fi | |
done | |
[ -n "$(jobs -p)" ] && wait -n | |
} | |
start_once() { | |
local startTime=$(date +%s) | |
start_all | |
local status=$? | |
local endTime=$(date +%s) | |
local runTime=$(( endTime - startTime )) | |
if (( runTime < delay )); then | |
delay=$(( delay * 2 )) | |
else | |
delay=1 | |
fi | |
[ "$status" -eq 0 ] && prefix="INFO:" || prefix="ERR:" | |
warn "${prefix} Exit code ${status}; ran for ${runTime}s; restarting in ${delay}s..." | |
sleep "$delay" | |
} | |
while true; do | |
start_once | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment