From ebfed5d168d242ce8d9ddd1581401ad9376a0102 Mon Sep 17 00:00:00 2001 From: hubian <908234780@qq.com> Date: Thu, 26 Mar 2026 17:13:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=BF=9B=E7=A8=8B?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=E8=84=9A=E6=9C=AC=20proc=5Fmonitor.sh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 监控指定进程名或 PID - 每 10 秒检测一次(可配置) - 进程消失时执行指定命令 - 支持日志记录和后台守护模式 --- README.md | 2 +- scripts/proc_monitor.sh | 240 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 1 deletion(-) create mode 100755 scripts/proc_monitor.sh diff --git a/README.md b/README.md index 5d21289..3c366e8 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ tools/ | 名称 | 路径 | 说明 | |------|------|------| -| - | - | 待添加 | +| proc_monitor.sh | scripts/proc_monitor.sh | 进程监控脚本,进程消失时执行指定命令 | --- diff --git a/scripts/proc_monitor.sh b/scripts/proc_monitor.sh new file mode 100755 index 0000000..ae40cd2 --- /dev/null +++ b/scripts/proc_monitor.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# ============================================================================= +# 进程监控脚本 +# 监控指定进程,当进程消失时执行指定命令 +# +# 用法: +# ./proc_monitor.sh -p <进程名> -c "<命令>" [-i 10] [-l /path/to/log] +# ./proc_monitor.sh --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 "$@"