Purpose:
Ensure that only one instance of a script runs at a time (mutual exclusion), preventing race conditions, duplicate work, or resource conflicts.
This pattern is commonly used for:
#!/usr/bin/env bash
set -euo pipefail
SCRIPT="$(basename "$0")"
UID="$(id -u)"
# select lock dir
if [ "$UID" -eq 0 ]; then
DIR="/run/lock/$SCRIPT"
mkdir -p "$DIR" && chmod 0755 "$DIR"
else
DIR="/tmp/$SCRIPT-$UID"
mkdir -p "$DIR" && chmod 0700 "$DIR"
fi
# acquire lock
exec 200>"$DIR/lock"
flock -n 200 || {
command -v logger >/dev/null 2>&1 \
&& logger -t "$SCRIPT" "already running" \
|| echo "$SCRIPT: already running" >&2
exit 1
}
echo "$$" 1>&200
Uses flock (kernel-level file locking) on a file descriptor
Lock is:
No PID file validation required
root user
/run/lock/<script>non-root user
/tmp/<script>-<uid>PID-based locking:
flock avoids all of these by delegating locking to the kernel.
Non-blocking (-n)
Reboot-safe
Crash-safe
This is a mutual exclusion mechanism, not a scheduler
The lock file’s existence is irrelevant — only the lock state matters
Safe to use in:
Not suitable for:
exec 200>/tmp/$(basename "$0")-$(id -u).lock
flock -n 200 || exit 1