Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save AnythingLinux/0456592a23248588f13d0e948846c5b4 to your computer and use it in GitHub Desktop.

Select an option

Save AnythingLinux/0456592a23248588f13d0e948846c5b4 to your computer and use it in GitHub Desktop.
Kill Zombies Automatically Linux Server
# Create script
nano /usr/local/bin/cleanup_zombies.sh
#!/bin/bash
# ============================================================
# zombie_manager.sh — Ubuntu Server Zombie Process Manager
# Usage: sudo bash zombie_manager.sh [--kill] [--log] [--watch]
# Options:
# --kill Auto-kill parent processes of zombies
# --log Log results to /var/log/zombie_manager.log
# --watch Continuous monitor mode (every 10 seconds)
# ============================================================
LOG_FILE="/var/log/zombie_manager.log"
AUTO_KILL=false
ENABLE_LOG=false
WATCH_MODE=false
INTERVAL=10
# Parse arguments
for arg in "$@"; do
case $arg in
--kill) AUTO_KILL=true ;;
--log) ENABLE_LOG=true ;;
--watch) WATCH_MODE=true ;;
esac
done
log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
echo "$msg"
if $ENABLE_LOG; then
echo "$msg" >> "$LOG_FILE"
fi
}
find_zombies() {
# Find all zombie (defunct) processes
ps aux | awk '$8 == "Z" {print $0}'
}
get_zombie_pids() {
ps -eo pid,stat | awk '$2 ~ /^Z/ {print $1}'
}
get_parent_pid() {
local pid=$1
ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' '
}
kill_parent() {
local zpid=$1
local ppid
ppid=$(get_parent_pid "$zpid")
if [[ -z "$ppid" || "$ppid" -le 1 ]]; then
log " SKIP: Parent PID $ppid is init/systemd — will not kill."
return 1
fi
local pname
pname=$(ps -p "$ppid" -o comm= 2>/dev/null || echo "unknown")
log " Sending SIGCHLD to parent PID $ppid ($pname)..."
kill -SIGCHLD "$ppid" 2>/dev/null
sleep 1
if ps -p "$zpid" > /dev/null 2>&1; then
log " Zombie $zpid persists. Sending SIGTERM to parent $ppid..."
kill -TERM "$ppid" 2>/dev/null
sleep 2
fi
if ps -p "$zpid" > /dev/null 2>&1; then
log " Zombie $zpid still alive. Sending SIGKILL to parent $ppid..."
kill -KILL "$ppid" 2>/dev/null
else
log " Zombie PID $zpid successfully reaped."
fi
}
scan_once() {
log "===== Zombie Process Scan ====="
local zombie_pids
zombie_pids=$(get_zombie_pids)
if [[ -z "$zombie_pids" ]]; then
log "No zombie processes found. System is clean."
return 0
fi
log "Zombie processes detected:"
echo ""
printf "%-8s %-8s %-6s %-8s %-20s %s\n" \
"PID" "PPID" "STAT" "USER" "STARTED" "COMMAND"
echo "------------------------------------------------------------------------"
local count=0
while IFS= read -r zpid; do
[[ -z "$zpid" ]] && continue
local ppid user started cmd stat
ppid=$(ps -o ppid= -p "$zpid" 2>/dev/null | tr -d ' ')
user=$(ps -o user= -p "$zpid" 2>/dev/null | tr -d ' ')
started=$(ps -o lstart= -p "$zpid" 2>/dev/null | xargs)
cmd=$(ps -o comm= -p "$zpid" 2>/dev/null)
stat=$(ps -o stat= -p "$zpid" 2>/dev/null)
printf "%-8s %-8s %-6s %-8s %-20s %s\n" \
"$zpid" "$ppid" "$stat" "$user" "$started" "$cmd"
((count++))
done <<< "$zombie_pids"
echo ""
log "Total zombies found: $count"
if $AUTO_KILL; then
log "--- Auto-kill mode enabled ---"
while IFS= read -r zpid; do
[[ -z "$zpid" ]] && continue
log "Processing zombie PID: $zpid"
kill_parent "$zpid"
done <<< "$zombie_pids"
log "--- Kill pass complete ---"
else
log "Tip: Re-run with --kill to auto-terminate parent processes."
fi
}
# Rotate log if larger than 5 MB
rotate_log() {
if $ENABLE_LOG && [[ -f "$LOG_FILE" ]]; then
local size
size=$(stat -c%s "$LOG_FILE" 2>/dev/null || echo 0)
if (( size > 5242880 )); then
mv "$LOG_FILE" "${LOG_FILE}.1"
log "Log rotated: ${LOG_FILE}.1"
fi
fi
}
# Main entry point
if $WATCH_MODE; then
log "Watch mode ON — scanning every ${INTERVAL}s. Press Ctrl+C to stop."
while true; do
rotate_log
scan_once
echo ""
sleep "$INTERVAL"
done
else
rotate_log
scan_once
fi
# Save and exit
# Make executable:
chmod +x /usr/local/bin/cleanup_zombies.sh
Scan only: sudo bash /usr/local/bin/cleanup_zombies.sh --log
Auto-kill + log: sudo bash /usr/local/bin/cleanup_zombies.sh --kill --log
Continuous watch: sudo bash /usr/local/bin/cleanup_zombies.sh --kill --log --watch
# Add cron:
crontab -e
# Run every 5 minutes (silent auto-kill + log)
*/5 * * * * /usr/local/bin/cleanup_zombies.sh --kill --log --watch >> /var/log/zombie_manager.log 2>&1
# Verify crontab was saved
sudo crontab -l
# Reboot Server
@AnythingLinux
Copy link
Copy Markdown
Author

AnythingLinux commented Apr 20, 2026

Using Daemon/Systemd mode

nano /etc/systemd/system/zombie-manager.service

[Unit]
Description=Zombie Process Auto-Manager
After=multi-user.target
Documentation=https://man7.org/linux/man-pages/man5/proc.5.html

[Service]
Type=simple
ExecStart=/usr/local/bin/cleanup_zombies.sh --kill --log --watch
Restart=on-failure
RestartSec=15
StandardOutput=journal
StandardError=journal
SyslogIdentifier=zombie-manager

NoNewPrivileges=false
ProtectSystem=false

[Install]
WantedBy=multi-user.target

Save and exit

Install & enable the systemd service

1. Copy the script to a system-wide path

sudo cp cleanup_zombies.sh /usr/local/bin/cleanup_zombies.sh
chmod +x /usr/local/bin/cleanup_zombies.sh

2. Create the service file

sudo nano /etc/systemd/system/zombie-manager.service

[Unit]
Description=Zombie Process Auto-Manager
After=multi-user.target
Documentation=https://man7.org/linux/man-pages/man5/proc.5.html

[Service]
Type=simple
ExecStart=/usr/local/bin/cleanup_zombies.sh --kill --log --watch
Restart=on-failure
RestartSec=15
StandardOutput=journal
StandardError=journal
SyslogIdentifier=zombie-manager

NoNewPrivileges=false
ProtectSystem=false

[Install]
WantedBy=multi-user.target

3. Reload systemd and enable the service

sudo systemctl daemon-reload
sudo systemctl enable zombie-manager
sudo systemctl start zombie-manager
sudo systemctl restart zombie-manager

4. Verify status

sudo systemctl status zombie-manager

5. Stream live logs

sudo journalctl -u zombie-manager -f

6. Disable / stop if needed

sudo systemctl stop zombie-manager
sudo systemctl disable zombie-manager

The service restarts automatically on failure (RestartSec=15s). Logs are accessible via journalctl -u zombie-manager and also written to /var/log/zombie_manager.log.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment