Created
August 30, 2024 19:53
-
-
Save kfiresmith/f553bab0bad409166e2f34eec91e5bbd to your computer and use it in GitHub Desktop.
Setting a PID file / lock file to prevent duplicate script runs (bash)
This file contains 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 | |
# Obtain the name of the script dynamically so that we can re-use this code block on any script | |
SCRIPT_FULLNAME="${0##*/}" | |
# Trim off the file extension if one is present | |
SCRIPT_TRIMMEDNAME="${SCRIPT_FULLNAME%.*}" | |
# /run is superior to /tmp, but we can't write a lock file there if we aren't root. | |
# We want to maintain the option of using this code block in scripts not run by root, | |
# so we fall back to using good old /tmp | |
LOCK_DIR="/run" | |
[ -w "$LOCK_DIR" ] || LOCK_DIR="/tmp" | |
LOCK_FILE="$LOCK_DIR/$SCRIPT_TRIMMEDNAME.lock" | |
# Function to remove the lock file on exit | |
cleanup() { | |
rm -f "$LOCK_FILE" | |
} | |
# Trap to ensure PID file is removed even if the script is interrupted | |
# This runs on exit whether the script was successful, failed, or interrupted. | |
trap cleanup EXIT | |
# Check if the PID file exists. If it already exists, we just exit so that we don't | |
# create a cron pileup by re-running the running script again over itself. | |
if [ -e "$LOCK_FILE" ]; then | |
echo "Script is already running. Exiting." | |
exit 1 | |
fi | |
# If we've made it this far, write the current PID to the PID file. Now we can | |
# proceed with running the actual script | |
echo $$ > "$LOCK_FILE" | |
# Do stuff below | |
# Remove the PID file (handled by the trap) | |
exit 0 |
In Python:
#!/usr/bin/env python3
import os
import sys
import atexit
# Obtain the name of the script dynamically so that we can re-use this code block on any script
script_fullname = os.path.basename(__file__)
# Trim off the file extension if one is present
script_trimmedname = os.path.splitext(script_fullname)[0]
# /run is superior to /tmp, but we can't write a lock file there if we aren't root.
# We want to maintain the option of using this code block in scripts not run by root,
# so we fall back to using good old /tmp
lock_dir = "/run" if os.access("/run", os.W_OK) else "/tmp"
lock_file = os.path.join(lock_dir, f"{script_trimmedname}.lock")
def cleanup():
"""Remove the lock file on exit."""
if os.path.exists(lock_file):
os.remove(lock_file)
# Register the cleanup function to run on script exit
atexit.register(cleanup)
# Check if the lock file exists. If it already exists, we just exit to prevent
# creating a cron pileup by re-running the running script over itself.
if os.path.exists(lock_file):
print("Script is already running. Exiting.")
sys.exit(1)
# If we've made it this far, write the current PID to the lock file.
with open(lock_file, 'w') as f:
f.write(str(os.getpid()))
# Do stuff below
# Exit (cleanup will be handled by atexit)
sys.exit(0)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Feedback welcome!