a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
364 lines
15 KiB
Bash
364 lines
15 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
#########################################################################################
|
|
#### process-top.sh — Show top CPU/memory consumers, zombies, and long-running procs ####
|
|
#### Provides a quick snapshot of process health and resource usage ####
|
|
#### ####
|
|
#### Author: Phil Connor ####
|
|
#### Contact: contact@mylinux.work ####
|
|
#### License: MIT ####
|
|
#### Version 1.00 ####
|
|
#### ####
|
|
#### Usage: ####
|
|
#### ./process-top.sh ####
|
|
#### ./process-top.sh --top 20 --section cpu,zombies ####
|
|
#### ./process-top.sh --min-runtime 48 ####
|
|
#### ####
|
|
#### See --help for all options. ####
|
|
#########################################################################################
|
|
|
|
set -euo pipefail
|
|
|
|
# ── Defaults ──────────────────────────────────────────────────────────
|
|
SECTIONS="${SECTIONS:-all}"
|
|
VERBOSE="${VERBOSE:-false}"
|
|
COLOR="${COLOR:-auto}"
|
|
TOP_N="${TOP_N:-10}"
|
|
MIN_RUNTIME="${MIN_RUNTIME:-24}"
|
|
|
|
# ── State ─────────────────────────────────────────────────────────────
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
readonly SCRIPT_NAME
|
|
|
|
# ── Colors ────────────────────────────────────────────────────────────
|
|
setup_colors() {
|
|
if [[ "$COLOR" == "never" ]]; then
|
|
RED="" GREEN="" YELLOW="" CYAN="" BOLD="" DIM="" RESET=""
|
|
return
|
|
fi
|
|
if [[ "$COLOR" == "always" ]] || [[ -t 1 ]]; then
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
DIM='\033[2m'
|
|
RESET='\033[0m'
|
|
else
|
|
RED="" GREEN="" YELLOW="" CYAN="" BOLD="" DIM="" RESET=""
|
|
fi
|
|
}
|
|
|
|
# ── Logging ───────────────────────────────────────────────────────────
|
|
log() { echo -e "${CYAN}[INFO]${RESET} $*"; }
|
|
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
|
|
|
|
# ── Helpers ───────────────────────────────────────────────────────────
|
|
section_header() {
|
|
echo ""
|
|
echo -e " ${BOLD}${CYAN}── $1 ──${RESET}"
|
|
echo ""
|
|
}
|
|
|
|
field() {
|
|
printf " ${BOLD}%-22s${RESET} %s\n" "$1" "$2"
|
|
}
|
|
|
|
field_color() {
|
|
printf " ${BOLD}%-22s${RESET} %b\n" "$1" "$2"
|
|
}
|
|
|
|
should_show() {
|
|
[[ "$SECTIONS" == "all" ]] || [[ ",$SECTIONS," == *",$1,"* ]]
|
|
}
|
|
|
|
value_color() {
|
|
local value="$1"
|
|
local int_val
|
|
int_val=$(printf "%.0f" "$value" 2>/dev/null || echo "0")
|
|
if [[ "$int_val" -ge 80 ]]; then
|
|
echo "$YELLOW"
|
|
else
|
|
echo "$GREEN"
|
|
fi
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# TOP CPU
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
show_cpu() {
|
|
section_header "Top ${TOP_N} by CPU Usage"
|
|
|
|
printf " ${BOLD}%-8s %-12s %6s %6s %10s %s${RESET}\n" "PID" "USER" "CPU%" "MEM%" "TIME" "COMMAND"
|
|
printf " %s\n" "$(printf '%.0s─' {1..72})"
|
|
|
|
ps -eo pid,user,pcpu,pmem,etime,comm --sort=-pcpu --no-headers 2>/dev/null | head -n "$TOP_N" | while IFS= read -r line; do
|
|
local pid user cpu mem etime comm
|
|
pid=$(echo "$line" | awk '{print $1}')
|
|
user=$(echo "$line" | awk '{print $2}')
|
|
cpu=$(echo "$line" | awk '{print $3}')
|
|
mem=$(echo "$line" | awk '{print $4}')
|
|
etime=$(echo "$line" | awk '{print $5}')
|
|
comm=$(echo "$line" | awk '{print $6}')
|
|
|
|
local cc mc
|
|
cc=$(value_color "$cpu")
|
|
mc=$(value_color "$mem")
|
|
|
|
printf " %-8s %-12s %b%5s%%%b %b%5s%%%b %10s %s\n" \
|
|
"$pid" "$user" "$cc" "$cpu" "$RESET" "$mc" "$mem" "$RESET" "$etime" "$comm"
|
|
done
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# TOP MEMORY
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
show_memory() {
|
|
section_header "Top ${TOP_N} by Memory Usage"
|
|
|
|
printf " ${BOLD}%-8s %-12s %6s %6s %10s %s${RESET}\n" "PID" "USER" "CPU%" "MEM%" "TIME" "COMMAND"
|
|
printf " %s\n" "$(printf '%.0s─' {1..72})"
|
|
|
|
ps -eo pid,user,pcpu,pmem,etime,comm --sort=-pmem --no-headers 2>/dev/null | head -n "$TOP_N" | while IFS= read -r line; do
|
|
local pid user cpu mem etime comm
|
|
pid=$(echo "$line" | awk '{print $1}')
|
|
user=$(echo "$line" | awk '{print $2}')
|
|
cpu=$(echo "$line" | awk '{print $3}')
|
|
mem=$(echo "$line" | awk '{print $4}')
|
|
etime=$(echo "$line" | awk '{print $5}')
|
|
comm=$(echo "$line" | awk '{print $6}')
|
|
|
|
local cc mc
|
|
cc=$(value_color "$cpu")
|
|
mc=$(value_color "$mem")
|
|
|
|
printf " %-8s %-12s %b%5s%%%b %b%5s%%%b %10s %s\n" \
|
|
"$pid" "$user" "$cc" "$cpu" "$RESET" "$mc" "$mem" "$RESET" "$etime" "$comm"
|
|
done
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# ZOMBIES
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
show_zombies() {
|
|
section_header "Zombie Processes"
|
|
|
|
local zombie_list
|
|
zombie_list=$(ps -eo pid,ppid,user,stat,comm --no-headers 2>/dev/null | awk '$4 ~ /^Z/')
|
|
|
|
if [[ -z "$zombie_list" ]]; then
|
|
echo -e " ${GREEN}No zombie processes found${RESET}"
|
|
return
|
|
fi
|
|
|
|
printf " ${BOLD}%-8s %-8s %-12s %-6s %s${RESET}\n" "PID" "PPID" "USER" "STAT" "COMMAND"
|
|
printf " %s\n" "$(printf '%.0s─' {1..55})"
|
|
|
|
echo "$zombie_list" | while IFS= read -r line; do
|
|
local pid ppid user stat comm
|
|
pid=$(echo "$line" | awk '{print $1}')
|
|
ppid=$(echo "$line" | awk '{print $2}')
|
|
user=$(echo "$line" | awk '{print $3}')
|
|
stat=$(echo "$line" | awk '{print $4}')
|
|
comm=$(echo "$line" | awk '{print $5}')
|
|
|
|
printf " ${RED}%-8s${RESET} %-8s %-12s ${RED}%-6s${RESET} %s\n" \
|
|
"$pid" "$ppid" "$user" "$stat" "$comm"
|
|
done
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# LONG-RUNNING
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
etime_to_hours() {
|
|
local etime="$1"
|
|
local days=0 hours=0 mins=0
|
|
|
|
if [[ "$etime" == *-* ]]; then
|
|
days=${etime%%-*}
|
|
etime=${etime#*-}
|
|
fi
|
|
|
|
local parts
|
|
IFS=: read -ra parts <<< "$etime"
|
|
local num_parts=${#parts[@]}
|
|
|
|
if [[ "$num_parts" -eq 3 ]]; then
|
|
hours=${parts[0]}
|
|
mins=${parts[1]}
|
|
elif [[ "$num_parts" -eq 2 ]]; then
|
|
hours=${parts[0]}
|
|
mins=${parts[1]}
|
|
elif [[ "$num_parts" -eq 1 ]]; then
|
|
mins=${parts[0]}
|
|
fi
|
|
|
|
# Remove leading zeros
|
|
days=$((10#$days))
|
|
hours=$((10#$hours))
|
|
mins=$((10#$mins))
|
|
|
|
echo $(( days * 24 + hours + (mins > 30 ? 1 : 0) ))
|
|
}
|
|
|
|
show_long_running() {
|
|
section_header "Long-Running Processes (> ${MIN_RUNTIME}h)"
|
|
|
|
printf " ${BOLD}%-8s %-12s %10s %6s %s${RESET}\n" "PID" "USER" "ELAPSED" "MEM%" "COMMAND"
|
|
printf " %s\n" "$(printf '%.0s─' {1..62})"
|
|
|
|
local found=0
|
|
ps -eo pid,user,etime,pmem,comm --no-headers 2>/dev/null | while IFS= read -r line; do
|
|
local pid user etime mem comm
|
|
pid=$(echo "$line" | awk '{print $1}')
|
|
user=$(echo "$line" | awk '{print $2}')
|
|
etime=$(echo "$line" | awk '{print $3}')
|
|
mem=$(echo "$line" | awk '{print $4}')
|
|
comm=$(echo "$line" | awk '{print $5}')
|
|
|
|
local run_hours
|
|
run_hours=$(etime_to_hours "$etime")
|
|
|
|
if [[ "$run_hours" -ge "$MIN_RUNTIME" ]]; then
|
|
printf " %-8s %-12s %10s %5s%% %s\n" "$pid" "$user" "$etime" "$mem" "$comm"
|
|
found=1
|
|
fi
|
|
done
|
|
|
|
if [[ "$found" -eq 0 ]]; then
|
|
echo -e " ${GREEN}No processes running longer than ${MIN_RUNTIME} hours${RESET}"
|
|
fi
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# SUMMARY
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
print_summary() {
|
|
echo ""
|
|
echo -e " ${BOLD}══════════════════════════════════════════${RESET}"
|
|
echo -e " ${BOLD}Process Summary${RESET}"
|
|
echo -e " ${BOLD}══════════════════════════════════════════${RESET}"
|
|
|
|
local total_procs zombie_count long_count
|
|
|
|
total_procs=$(ps -e --no-headers 2>/dev/null | wc -l)
|
|
zombie_count=$(ps -eo stat --no-headers 2>/dev/null | awk '/^Z/{c++} END{print c+0}')
|
|
long_count=$(ps -eo etime --no-headers 2>/dev/null | while IFS= read -r etime; do
|
|
etime=$(echo "$etime" | xargs)
|
|
local h
|
|
h=$(etime_to_hours "$etime")
|
|
if [[ "$h" -ge "$MIN_RUNTIME" ]]; then
|
|
echo "1"
|
|
fi
|
|
done | wc -l)
|
|
|
|
field "Total processes:" "$total_procs"
|
|
|
|
if [[ "$zombie_count" -gt 0 ]]; then
|
|
field_color "Zombie processes:" "${RED}${zombie_count}${RESET}"
|
|
else
|
|
field_color "Zombie processes:" "${GREEN}0${RESET}"
|
|
fi
|
|
|
|
field "Long-running (>${MIN_RUNTIME}h):" "$long_count"
|
|
|
|
echo ""
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# USAGE
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
${SCRIPT_NAME} — Show top CPU/memory consumers, zombies, and long-running processes
|
|
|
|
USAGE:
|
|
${SCRIPT_NAME} [OPTIONS]
|
|
|
|
OPTIONS:
|
|
--top N Number of processes to show (default: ${TOP_N})
|
|
--min-runtime HOURS Long-running threshold in hours (default: ${MIN_RUNTIME})
|
|
--section SECTIONS Comma-separated sections to show (default: all)
|
|
Available: cpu, memory, zombies, long-running
|
|
--verbose Enable debug output
|
|
--no-color Disable colored output
|
|
--help Show this help
|
|
|
|
ENVIRONMENT VARIABLES:
|
|
TOP_N Number of top processes (default: 10)
|
|
MIN_RUNTIME Long-running threshold in hours (default: 24)
|
|
SECTIONS Sections to display (default: all)
|
|
COLOR Color mode: auto, always, never (default: auto)
|
|
|
|
EXAMPLES:
|
|
# Full process overview
|
|
./process-top.sh
|
|
|
|
# Top 20 CPU consumers
|
|
./process-top.sh --top 20 --section cpu
|
|
|
|
# Find zombies and long-running processes
|
|
./process-top.sh --section zombies,long-running
|
|
|
|
# Processes running longer than 48 hours
|
|
./process-top.sh --min-runtime 48 --section long-running
|
|
EOF
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# ARGUMENT PARSING
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--top)
|
|
TOP_N="$2"; shift 2 ;;
|
|
--min-runtime)
|
|
MIN_RUNTIME="$2"; shift 2 ;;
|
|
--section)
|
|
SECTIONS="$2"; shift 2 ;;
|
|
--verbose)
|
|
VERBOSE="true"; shift ;;
|
|
--no-color)
|
|
COLOR="never"; shift ;;
|
|
--help|-h)
|
|
setup_colors
|
|
usage
|
|
exit 0 ;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
echo "Run ${SCRIPT_NAME} --help for usage" >&2
|
|
exit 1 ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# MAIN
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
setup_colors
|
|
|
|
echo ""
|
|
echo -e "${BOLD}Process Monitor — $(hostname -f 2>/dev/null || hostname)${RESET}"
|
|
echo -e "${DIM}$(date '+%Y-%m-%d %H:%M:%S %Z')${RESET}"
|
|
|
|
should_show "cpu" && show_cpu
|
|
should_show "memory" && show_memory
|
|
should_show "zombies" && show_zombies
|
|
should_show "long-running" && show_long_running
|
|
|
|
print_summary
|
|
}
|
|
|
|
main "$@"
|