Skip to content

用AI写了个简单的启动停止脚本 #12

@Cathgao

Description

@Cathgao

感谢gemini
可使用systemd管理napcat,不影响原来的TUI,方便开机运行等用途
已在ubuntu24.04.3测试

脚本内容:

#!/bin/bash

# 确定用户与目录 (适配 Systemd 环境)
TARGET_USER="${USER:-$(whoami)}"
TARGET_USER_HOME="${HOME:-/home/$TARGET_USER}"

# 核心路径定义
INSTALL_BASE_DIR="$TARGET_USER_HOME/Napcat"
RUN_DIR="$INSTALL_BASE_DIR/run"
LOG_DIR="$INSTALL_BASE_DIR/log"
# QQ 程序路径
QQ_EXECUTABLE="$INSTALL_BASE_DIR/opt/QQ/qq"
# Napcat 配置文件路径
NAPCAT_DIR="$INSTALL_BASE_DIR/opt/QQ/resources/app/app_launcher/napcat"
CONFIG_DIR="$NAPCAT_DIR/config"

# 确保运行时目录存在
mkdir -p "$RUN_DIR" "$LOG_DIR"


# 递归获取子进程 PID (用于彻底停止)
_get_all_descendant_pids() {
    local pids=$(pgrep -P "$1")
    for pid in $pids; do
        echo "$pid"
        _get_all_descendant_pids "$pid"
    done
}

# 自动从配置文件中获取第一个 QQ 账号
get_qq_account() {
    local config_file
    config_file=$(ls "$CONFIG_DIR"/onebot11_*.json 2>/dev/null | head -n 1)

    if [[ -z "$config_file" ]]; then
        echo "错误: 在 $CONFIG_DIR 下未找到配置文件 (onebot11_*.json)。"
        exit 1
    fi

    local filename=$(basename "$config_file")
    if [[ "$filename" =~ onebot11_([0-9]+)\.json ]]; then
        echo "${BASH_REMATCH[1]}"
    else
        echo "错误: 无法从文件名 $filename 中解析 QQ 号。"
        exit 1
    fi
}

stop_napcat() {
    echo ">>> 正在停止 Napcat..."
    
    local candidate_pids
    local final_pids=()
    readarray -t candidate_pids < <(pgrep -f ".*/qq --no-sandbox -q [0-9]{4,}")

    if [[ ${#candidate_pids[@]} -gt 0 ]]; then
        for pid in "${candidate_pids[@]}"; do
            local ppid=$(ps -o ppid= -p "$pid" | tr -d ' ')
            local is_child=false
            for other_pid in "${candidate_pids[@]}"; do
                if [[ "$ppid" == "$other_pid" ]]; then
                    is_child=true; break
                fi
            done
            if ! $is_child; then final_pids+=("$pid"); fi
        done
    fi

    if [[ ${#final_pids[@]} -eq 0 ]]; then
        echo "未发现正在运行的 Napcat 进程。"
        [[ -f "$RUN_DIR/napcat.pid" ]] && rm -f "$RUN_DIR/napcat.pid"
        return 0
    fi

    echo "发现进程 (PID: ${final_pids[*]}), 正在终止..."
    local all_stopped=true
    
    for pid in "${final_pids[@]}"; do
        local all_pids_to_kill=("$pid" $(_get_all_descendant_pids "$pid"))
        kill "${all_pids_to_kill[@]}" 2>/dev/null
    done
    
    sleep 2

    for pid in "${final_pids[@]}"; do
        if kill -0 "$pid" 2>/dev/null; then
            local all_pids_to_kill=("$pid" $(_get_all_descendant_pids "$pid"))
            echo "进程顽固,执行强制清理 (kill -9)..."
            kill -9 "${all_pids_to_kill[@]}" 2>/dev/null
            sleep 1
        fi
        if kill -0 "$pid" 2>/dev/null; then all_stopped=false; fi
    done

    if $all_stopped; then
        echo "Napcat 已停止。"
        rm -f "$RUN_DIR/napcat.pid"
    else
        echo "警告: 部分进程可能未停止,请手动检查。"
        exit 1
    fi
}

start_napcat() {
    echo ">>> 准备启动 Napcat..."

    if ! command -v xvfb-run &> /dev/null; then
        echo "错误: 未找到 'xvfb-run' 命令。请先安装。"
        exit 1
    fi

    local qq_account
    qq_account=$(get_qq_account)
    if [[ $? -ne 0 ]]; then echo "$qq_account"; exit 1; fi
    
    local log_file="$LOG_DIR/napcat_${qq_account}.log"
    echo "目标账号: $qq_account"
    echo "日志路径: $log_file"
    echo "注意: 日志将同时输出到 屏幕(Systemd) 和 文件。"

    # 清理旧进程
    stop_napcat > /dev/null 2>&1

    echo "正在启动进程..."
    echo "$$" > "$RUN_DIR/napcat.pid"

    exec > >(tee -a "$log_file") 2>&1
    exec xvfb-run -a "$QQ_EXECUTABLE" --no-sandbox -q "$qq_account"

}


case "$1" in
    start)
        start_napcat
        ;;
    stop)
        stop_napcat
        ;;
    restart)
        stop_napcat
        sleep 1
        start_napcat
        ;;
    *)
        echo "用法: $0 {start|stop|restart}"
        exit 1
        ;;
esac

配套的systemd服务文件:

[Unit]
Description=Napcat QQ Bot Service
After=network.target network-online.target
Wants=network-online.target

[Service]
# 【修改】替换为你的实际用户名
User=ubuntu
Group=ubuntu

Type=simple
#替换你的napcat安装目录
WorkingDirectory=/home/ubuntu/Napcat

# 指向该脚本路径
ExecStart=/bin/bash /home/ubuntu/Napcat/napcat.sh start

# 停止时执行清理逻辑
ExecStop=/bin/bash /home/ubuntu/Napcat/napcat.sh stop

Restart=on-failure
RestartSec=10s

# 资源限制(可选,防止内存泄漏)
# MemoryMax=1G

[Install]
WantedBy=multi-user.target

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions