Last active
April 20, 2026 21:48
-
-
Save AnythingLinux/0456592a23248588f13d0e948846c5b4 to your computer and use it in GitHub Desktop.
Kill Zombies Automatically Linux Server
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
| # 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 |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.