Files
tools/scripts/proc_monitor.sh
hubian ebfed5d168 feat: 添加进程监控脚本 proc_monitor.sh
- 监控指定进程名或 PID
- 每 10 秒检测一次(可配置)
- 进程消失时执行指定命令
- 支持日志记录和后台守护模式
2026-03-26 17:13:11 +08:00

241 lines
5.7 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# =============================================================================
# 进程监控脚本
# 监控指定进程,当进程消失时执行指定命令
#
# 用法:
# ./proc_monitor.sh -p <进程名> -c "<命令>" [-i 10] [-l /path/to/log]
# ./proc_monitor.sh --pid <PID> -c "<命令>" [-i 10] [-l /path/to/log]
#
# 参数:
# -p, --process 要监控的进程名
# --pid 要监控的进程 PID
# -c, --command 进程消失后要执行的命令(必填)
# -i, --interval 检测间隔(秒,默认 10
# -l, --log 日志文件路径(可选)
# -d, --daemon 后台运行模式
# -h, --help 显示帮助
#
# 示例:
# ./proc_monitor.sh -p "myapp" -c "systemctl restart myapp" -i 10
# ./proc_monitor.sh --pid 1234 -c "echo 'Process died' >> /tmp/alert.log" -d
# =============================================================================
set -euo pipefail
# 默认配置
INTERVAL=10
LOG_FILE=""
DAEMON_MODE=false
PROCESS_NAME=""
TARGET_PID=""
EXEC_COMMAND=""
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 日志函数
log() {
local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
echo -e "$msg"
if [[ -n "$LOG_FILE" ]]; then
echo -e "$msg" >> "$LOG_FILE"
fi
}
log_info() {
log "${GREEN}[INFO]${NC} $1"
}
log_warn() {
log "${YELLOW}[WARN]${NC} $1"
}
log_error() {
log "${RED}[ERROR]${NC} $1"
}
# 显示帮助
show_help() {
sed -n '/^# ==/,/^# ==/p' "$0" | sed 's/^# //' | sed 's/^#//'
}
# 解析参数
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-p|--process)
PROCESS_NAME="$2"
shift 2
;;
--pid)
TARGET_PID="$2"
shift 2
;;
-c|--command)
EXEC_COMMAND="$2"
shift 2
;;
-i|--interval)
INTERVAL="$2"
shift 2
;;
-l|--log)
LOG_FILE="$2"
shift 2
;;
-d|--daemon)
DAEMON_MODE=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
done
}
# 验证参数
validate_args() {
if [[ -z "$PROCESS_NAME" && -z "$TARGET_PID" ]]; then
log_error "必须指定进程名 (-p) 或 PID (--pid)"
exit 1
fi
if [[ -n "$PROCESS_NAME" && -n "$TARGET_PID" ]]; then
log_error "不能同时指定进程名和 PID请二选一"
exit 1
fi
if [[ -z "$EXEC_COMMAND" ]]; then
log_error "必须指定要执行的命令 (-c)"
exit 1
fi
if ! [[ "$INTERVAL" =~ ^[0-9]+$ ]] || [[ "$INTERVAL" -lt 1 ]]; then
log_error "检测间隔必须是正整数(秒)"
exit 1
fi
}
# 检查进程是否存在
check_process() {
if [[ -n "$TARGET_PID" ]]; then
# 通过 PID 检查
kill -0 "$TARGET_PID" 2>/dev/null
else
# 通过进程名检查
pgrep -x "$PROCESS_NAME" >/dev/null 2>&1 || \
pgrep -f "$PROCESS_NAME" >/dev/null 2>&1
fi
}
# 获取进程信息
get_process_info() {
if [[ -n "$TARGET_PID" ]]; then
echo "PID: $TARGET_PID"
else
local pid
pid=$(pgrep -x "$PROCESS_NAME" 2>/dev/null | head -1 || \
pgrep -f "$PROCESS_NAME" 2>/dev/null | head -1 || echo "unknown")
echo "进程名: $PROCESS_NAME (PID: $pid)"
fi
}
# 监控循环
monitor() {
log_info "开始监控 $(get_process_info)"
log_info "检测间隔: ${INTERVAL}"
log_info "触发命令: $EXEC_COMMAND"
log_info "按 Ctrl+C 停止监控"
echo "---"
local check_count=0
local start_time
start_time=$(date +%s)
while true; do
check_count=$((check_count + 1))
if ! check_process; then
log_warn "检测到进程已消失!"
log_info "执行命令: $EXEC_COMMAND"
# 执行命令并记录结果
if eval "$EXEC_COMMAND"; then
log_info "命令执行成功"
else
log_error "命令执行失败,退出码: $?"
fi
# 统计信息
local end_time
end_time=$(date +%s)
local duration=$((end_time - start_time))
log_info "监控时长: ${duration}秒,共检测 ${check_count}"
break
fi
# 每 6 次检测(约 1 分钟)输出一次存活确认
if [[ $((check_count % 6)) -eq 0 ]]; then
log_info "进程正常运行中... (已检测 ${check_count} 次)"
fi
sleep "$INTERVAL"
done
}
# 后台运行模式
run_daemon() {
local script_path
script_path=$(realpath "$0")
local args=""
# 重新构建参数(去掉 -d
if [[ -n "$PROCESS_NAME" ]]; then
args="-p '$PROCESS_NAME'"
elif [[ -n "$TARGET_PID" ]]; then
args="--pid '$TARGET_PID'"
fi
args="$args -c '$EXEC_COMMAND' -i $INTERVAL"
[[ -n "$LOG_FILE" ]] && args="$args -l '$LOG_FILE'"
log_info "以守护模式启动..."
log_info "日志将输出到: ${LOG_FILE:-stdout}"
# 使用 nohup 后台运行
eval "nohup bash $script_path $args >/dev/null 2>&1 &"
local pid=$!
log_info "守护进程 PID: $pid"
}
# 主函数
main() {
parse_args "$@"
validate_args
if [[ "$DAEMON_MODE" == true ]]; then
run_daemon
else
monitor
fi
}
# 捕获信号
trap 'log_info "监控已停止"; exit 0' INT TERM
# 运行主函数
main "$@"