让AI帮忙写的一些脚本
运维备忘 4

云崽持久化备份和迁移恢复

帮写我两个脚本

第一个脚本我需要实现:

提取位于/opt/docker里的Yunzai目录的config/config/里的bot.yaml、group.yaml、other.yaml,提取Yunzai里的data、resources目录,提取Yunzai/plugins里的目录体积小于100mb的文件夹,要保留提取文件的yunzai里目录结构位置生成一个压缩包,对于Yunzai/plugins里的大于100mb以上的目录,分别提取里面的git clone的git仓库链接汇总待用,并且提取Yunzai/plugins里大于100mb的各个目录里面的config文件夹,其中waves-plugin/resources/rolepic 也保留,以上仍然保留目录结构,另外建立备份压缩包。以上两个压缩包和git链接的txt放在/opt/docker目录。

AI:

#!/bin/bash
set -euo pipefail

# 路径配置
yunzai_dir="/opt/docker/Yunzai"
backup_dir="/opt/docker"
tmp1="${backup_dir}/tmp_part1"  # 小文件临时目录
tmp2="${backup_dir}/tmp_part2"  # 大文件临时目录
git_links="${backup_dir}/git_clone_links.txt"

# 清理旧文件
rm -rf "$tmp1" "$tmp2" "${backup_dir}/backup_part1.tar.gz" "${backup_dir}/backup_part2.tar.gz" "$git_links"

# 创建临时目录
mkdir -p "$tmp1" "$tmp2"

# 智能复制函数(自动创建目录结构)
preserve_copy() {
    local src="$1"
    local dest_root="$2"
    local relative_path="${src#$yunzai_dir/}"
    
    if [[ -e "$src" ]]; then
        mkdir -p "${dest_root}/$(dirname "$relative_path")"
        cp -rf "$src" "${dest_root}/$relative_path"
    else
        echo "警告: 跳过不存在的文件 $src"
    fi
}

# Part1:处理小文件备份
echo "正在收集第一部分数据..."
# 复制配置文件
for config in bot.yaml group.yaml other.yaml; do
    preserve_copy "${yunzai_dir}/config/config/$config" "$tmp1"
done

# 复制核心目录
for dir in data resources; do
    preserve_copy "${yunzai_dir}/$dir" "$tmp1"
done

# 处理小插件(≤100MB)
find "${yunzai_dir}/plugins" -maxdepth 1 -type d | while read -r plugin; do
    if [[ "$plugin" != "${yunzai_dir}/plugins" ]]; then
        size_kb=$(du -sk "$plugin" | cut -f1)
        if (( size_kb <= 100000 )); then  # 100MB=100000KB
            preserve_copy "$plugin" "$tmp1"
        fi
    fi
done

# Part2:处理大插件相关数据
echo "正在收集第二部分数据..."
echo "# 需要手动克隆的插件列表" > "$git_links"

find "${yunzai_dir}/plugins" -maxdepth 1 -type d | while read -r plugin; do
    if [[ "$plugin" != "${yunzai_dir}/plugins" ]]; then
        size_kb=$(du -sk "$plugin" | cut -f1)
        if (( size_kb > 100000 )); then  # 精确100MB判断
            # 记录git信息
            if [[ -d "${plugin}/.git" ]]; then
                git_url=$(git -C "$plugin" config --get remote.origin.url 2>/dev/null || true)
                if [[ -n "$git_url" ]]; then
                    echo "插件: $(basename "$plugin")" >> "$git_links"
                    echo "git clone $git_url" >> "$git_links"
                    echo "" >> "$git_links"
                fi
            fi
            
            # 复制config目录
            if [[ -d "${plugin}/config" ]]; then
                preserve_copy "${plugin}/config" "$tmp2"
            fi
            
            # 特殊处理waves-plugin的rolepic
            if [[ "$(basename "$plugin")" == "waves-plugin" ]]; then
                rolepic_src="${plugin}/resources/rolePic"
                if [[ -d "$rolepic_src" ]]; then
                    preserve_copy "$rolepic_src" "$tmp2"
                fi
            fi
        fi
    fi
done

# 创建压缩包(使用tar.gz格式)
echo "正在生成压缩文件..."
tar -czf "${backup_dir}/yunzai_backup_part1.tar.gz" -C "$tmp1" .
tar -czf "${backup_dir}/yunzai_backup_part2.tar.gz" -C "$tmp2" .

# 清理临时文件
rm -rf "$tmp1" "$tmp2"

echo "操作完成!生成文件:"
ls -lh "${backup_dir}/yunzai_backup_part1.tar.gz" "${backup_dir}/yunzai_backup_part2.tar.gz" "$git_links"

第二个脚本

第二个脚本我需要实现

执行下面这个命令,

DIR=/opt/docker/Yunzai CMD=yz DKNAME=yunzai NETWORK=1panel-network bash <(curl -L https://gitee.com/TimeRainStarSky/Yunzai/raw/main/lib/tools/docker.sh)

直到名为yunzai的容器运行后,进入容器内部终端(容器内终端初始目录已经是Yunzai),执行多个 git clone前面让你提取仓库git链接的的多个插件项目仓库到Yunzai下的plugins文件夹内,完成后退出容器终端。解压位于/opt/docker的两个压缩包到Yunzai目录覆盖。解压完后再次进入容器终端,遍历Yunazi/plugins里的所有插件目录,在里面分别执行pnpm i 安装依赖,无需安装依赖的插件目录跳过。

注意容器里已经有git和pnpm等我要让你用到的环境,无需再安装。

安装完依赖后重启yunzai容器。

AI:

#!/bin/bash
set -euo pipefail

# 配置参数
export DIR="/opt/docker/Yunzai"
export CMD="yz"
export DKNAME="yunzai"
export NETWORK="1panel-network"
backup_dir="/opt/docker"
git_links="${backup_dir}/git_clone_links.txt"

# 彩色输出定义
RED='\033[31m'
GREEN='\033[32m'
YELLOW='\033[33m'
BLUE='\033[34m'
RESET='\033[0m'
CYAN='\033[36m'  # 添加此行

# GitHub镜像代理配置(可自定义顺序)
GITHUB_PROXY_FORMATS=(
    "https://gitclone.com/github.com/{author}/{repo}"
    "https://ghproxy.357361.xyz/github.com/{author}/{repo}"
    # "https://hub.fastgit.org/{author}/{repo}"  # 可添加更多镜像源
)

# 阶段1:部署新容器
echo -e "${BLUE}▌阶段1/5 正在部署新容器...${RESET}"
if ! bash <(curl -fsSL https://gitee.com/TimeRainStarSky/Yunzai/raw/main/lib/tools/docker.sh); then
    echo -e "${RED}错误:容器部署失败!${RESET}"
    exit 1
fi

# 等待容器启动
echo -ne "${YELLOW}等待容器启动...${RESET}"
until docker inspect --format '{{.State.Running}}' "$DKNAME" | grep -q "true"; do
    sleep 2
    echo -n "."
done
echo -e "${GREEN} 已运行!${RESET}"

# 阶段2:安装Git插件(增强代理重试版+存在性检查)
echo -e "${BLUE}▌阶段2/5 正在安装Git插件...${RESET}"

# 新增文件存在性检查(带彩色路径显示)
if [[ ! -f "$git_links" ]]; then
    echo -e "${YELLOW}▌未检测到Git链接文件[${CYAN}${git_links}${YELLOW}],跳过插件克隆阶段${RESET}"
else
    clone_cmds=$(grep -E '^git clone ' "$git_links" | sed 's/^ *//;s/ *$//')
    if [[ -n "$clone_cmds" ]]; then
        docker exec -i "$DKNAME" bash <<EOF
set -eo pipefail
cd plugins || { echo -e "${RED}▌错误:无法进入plugins目录${RESET}" >&2; exit 1; }

# 代理重试克隆函数(带耗时统计)
clone_with_proxy() {
    original_url="\$1"
    target_dir="\$2"
    echo -e "原始地址: \${YELLOW}\${original_url}${RESET}"
    
    # 解析GitHub项目路径
    if [[ \$original_url =~ ^https://github.com/([^/]+)/([^/]+)(/|\.git)?$ ]]; then
        author="\${BASH_REMATCH[1]}"
        repo="\${BASH_REMATCH[2]%.git}"
        retry_sources=("\$original_url")
        
        # 生成代理地址
        for proxy_format in ${GITHUB_PROXY_FORMATS[@]}; do
            proxy_url="\${proxy_format//\{author\}/\$author}"
            proxy_url="\${proxy_url//\{repo\}/\$repo}"
            retry_sources+=("\$proxy_url")
        done
    else
        echo -e "${YELLOW}▌非GitHub地址,直接尝试克隆${RESET}"
        retry_sources=("\$original_url")
    fi

    # 依次尝试所有克隆源
    for url in "\${retry_sources[@]}"; do
        echo -n "尝试克隆: \${url} ... "
        if git clone --progress "\${url}" "\$target_dir" 2>&1 ; then
            echo -e "${GREEN}成功${RESET}"
            return 0
        fi
        status_code=\$?
        echo -e "${RED}失败 (代码:\$status_code)${RESET}"
        rm -rf "\$target_dir" 2>/dev/null || true
    done

    echo -e "${RED}▌所有镜像源尝试均失败!${RESET}"
    return 1
}

# 执行克隆命令(带存在性检查和错误处理)
exit_status=0
while read -r cmd; do
    args=(\$cmd)
    url="\${args[2]}"
    dir="\${args[3]:-}"
    
    # 计算目标目录路径
    if [[ -n "\$dir" ]]; then
        clone_dir="\${dir}"
    else
        clone_dir="\$(basename "\$url" .git)"
    fi

    # 目录存在性检查
    if [ -d "\$clone_dir" ]; then
        echo -e "\n${YELLOW}▌检测到现有插件: \${clone_dir}${RESET}"
        echo -e "${YELLOW}  ▌目录已存在,跳过克隆操作${RESET}"
        continue
    fi
    
    # 开始克隆流程
    echo -e "\n▌克隆项目: \${YELLOW}\${clone_dir}${RESET}"
    SECONDS=0
    if ! clone_with_proxy "\$url" "\$clone_dir"; then
        echo -e "${RED}▌严重: 插件克隆失败,终止流程!${RESET}"
        exit_status=3
        break
    fi
    echo -e "耗时: ${MAGENTA}\${SECONDS}s${RESET}"
done <<< "$clone_cmds"

exit \$exit_status
EOF

        # Docker执行结果检查
        if [ \$? -ne 0 ]; then
            echo -e "${RED}▌错误:插件安装过程中发生致命错误${RESET}"
            exit 4
        fi
    else
        echo -e "${YELLOW}▌文件中未找到有效的插件仓库链接${RESET}"
    fi
fi
# 宿主机验证提示
echo -e "\n${GREEN}插件同步完成,请检查宿主机目录:"
echo -e "  ${YELLOW}/opt/docker/Yunzai/plugins${RESET}"



# 阶段3:恢复备份数据
echo -e "${BLUE}▌阶段3/5 正在恢复备份...${RESET}"

# 设置nullglob避免未匹配时保留通配符
shopt -s nullglob
backup_files=("${backup_dir}"/yunzai_backup_part*.tar.gz)
shopt -u nullglob  # 恢复原设置

temp_dir=$(mktemp -d -p "$backup_dir")

if [ ${#backup_files[@]} -eq 0 ]; then
    echo -e "${YELLOW}未找到备份压缩包,已跳过解压步骤${RESET}"
    rm -rf "$temp_dir"  # 没有文件时也删除临时目录
else
    for backup in "${backup_files[@]}"; do
        echo -e "处理备份文件: ${YELLOW}$(basename "$backup")${RESET}"

        
        # 直接解压到宿主机持久化目录(保留所有属性)
        if ! tar -xzpf "$backup" -C "$DIR" --warning=no-unknown-keyword 2>/tmp/tar_error.log; then
            echo -e "${RED}错误: 解压失败,详情:${RESET}"
            cat /tmp/tar_error.log
            rm -rf "$temp_dir"
            exit 4
        fi
        
        # 验证解压文件数量
        expected_files=$(tar -tzf "$backup" | wc -l)
        actual_files=$(find "$DIR" -type f | wc -l)
        if [[ "$actual_files" -lt "$expected_files" ]]; then
            echo -e "${YELLOW}警告: 解压文件数量不足 (应有:$expected_files 现有:$actual_files)${RESET}"
        fi
    done 
    rm -rf "$temp_dir"  # 所有解压完成后删除临时目录
  
fi



# 阶段4:安装插件依赖(增强版)
echo -e "${BLUE}▌阶段4/5 正在安装插件依赖...${RESET}"
docker exec -i "$DKNAME" bash <<'EOF'
set -eo pipefail
log_dir="/root/Yunzai/plugins/_install_logs"
mkdir -p "$log_dir"
cd /root/Yunzai/plugins || exit 1

# 设置npm镜像源
npm config set registry https://registry.npmmirror.com

find . -maxdepth 1 -type d -print0 | while IFS= read -r -d '' plugin; do
    if [[ "$plugin" != "." ]]; then
        plugin_name="${plugin#./}"
        log_file="${log_dir}/${plugin_name}_$(date +%Y%m%d-%H%M%S).log"
        
        echo "▌处理插件: ${plugin_name}"
        {
            echo "工作目录: $(pwd)/${plugin_name}"
            cd "$plugin_name" || { echo "无法进入目录"; exit 1; }
            
            # 检查package.json是否存在
            if [ ! -f package.json ]; then
                echo "未找到package.json,跳过依赖安装"
                exit 0
            fi

            echo "开始安装依赖..."
            pnpm install --frozen-lockfile \
                --reporter=append-only \
                --prefer-offline 2>&1
            
            echo "依赖安装完成"
        } | tee "$log_file" || {
            echo "此插件安装失败,已记录日志:$log_file"
            continue
        }
    fi
done
EOF


# 阶段5:重启容器
echo -e "${BLUE}▌阶段5/5 正在重启容器...${RESET}"
docker stop "$DKNAME" && docker rm "$DKNAME"
docker run -d --name "$DKNAME" --network 1panel-network -p 7536-7540:2536-2540 --restart unless-stopped trss:yunzai



# 最终状态检查
echo -e "\n${GREEN}恢复流程已完成!容器状态:${RESET}"
docker ps -f name="$DKNAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

NAPCATqq持久化路径清理脚本

#!/bin/bash

# Napcat的基础目录(可修改)
BASE_DIR="/opt/docker/napcat"

# 要清理的用户目录(可修改,以逗号分隔的列表)
USER_DIRS="napcat357,napcat202,napcat304"

# 清理指定路径的函数
cleanup() {
    local base_dir=$1
    local user_dir=$2
    
    echo "正在清理用户目录: $user_dir"
    
    # 清理 QQ/NapCat/temp
    local temp_dir="$base_dir/$user_dir/QQ/NapCat/temp"
    if [ -d "$temp_dir" ]; then
        echo "正在删除 $temp_dir 中的内容"
        rm -rf "$temp_dir"/*
        mkdir -p "$temp_dir"
    fi
    
    # 查找所有 nt_qq_* 目录
    local qq_dirs=$(find "$base_dir/$user_dir/QQ" -type d -name "nt_qq_*" 2>/dev/null)
    
    for qq_dir in $qq_dirs; do
        echo "正在处理QQ目录: $qq_dir"
        
        # 清理数据库文件
        local db_dir="$qq_dir/nt_db"
        if [ -d "$db_dir" ]; then
            echo "正在从 $db_dir 删除数据库文件"
            rm -f "$db_dir/nt_msg.db" "$db_dir/group_msg_fts_db"
        fi
        
        # 清理数据目录
        local data_dir="$qq_dir/nt_data"
        if [ -d "$data_dir" ]; then
            echo "正在清理 $data_dir 中的目录"
            for subdir in Video log Pic File Ptt avatar; do
                if [ -d "$data_dir/$subdir" ]; then
                    echo "正在删除 $data_dir/$subdir 中的内容"
                    rm -rf "$data_dir/$subdir"/*
                    mkdir -p "$data_dir/$subdir"
                fi
            done
        fi
    done
}

# 主脚本
IFS=',' read -ra USERS <<< "$USER_DIRS"
for user in "${USERS[@]}"; do
    cleanup "$BASE_DIR" "$user"
done

echo "清理完成!"

让AI帮忙写的一些脚本
http://localhost:8090/archives/trssyunzaib
作者
Administrator
发布于
更新于
许可