一、脚本清单与定位

1.1 目录中的主要文件

  • mysql_single_instance_5.6-8.0_install_uninstall.sh:单实例版本管理脚本。
  • mysql_multi_instance_5.6-8.0_install_uninstall.sh:多实例版本管理脚本。
  • 脚本说明.txt:给出了多实例和单实例的登录命令示例。

1.2 这组脚本的共同价值

  • 同一套目录支持多版本切换。
  • 自动完成解压、初始化、配置文件生成和 systemd 服务注册。
  • 安装失败时会输出日志,便于定位问题。

二、单实例脚本整理

2.1 安装流程

precheck
install_mysql "8.0" "mysql-8.0"

cat > /etc/my.cnf <<EOF
[mysql]
socket=/tmp/mysql.sock

[mysqld]
user=mysql
port=3306
socket=/tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/data/mysql/data
server_id=1
EOF

2.2 脚本里值得保留的细节

  • 通过 systemctl is-active 阻止重复安装。
  • 通过等待 socket 文件出现来确认实例真的启动完成。
  • 根据 5.6、5.7、8.0 的差异切换不同的初始化和改密方式。

三、多实例脚本整理

3.1 多实例的核心变量

service_name="mysqld${port}"
base_dir="/usr/local/mysql${version_suffix}"
data_dir="/data/${port}/data"
socket_path="/tmp/mysql${port}.sock"

3.2 多实例的典型配置方式

cat > "${data_dir}/my.cnf" <<EOF
[mysql]
socket=${socket_path}

[mysqld]
user=mysql
port=${port}
socket=${socket_path}
basedir=${base_dir}
datadir=${data_dir}
server_id=${port}
EOF

3.3 目录说明文件中给出的登录方式

mysql5.6 -uroot -p<your-password> -S /tmp/mysql3356.sock
mysql5.7 -uroot -p<your-password> -S /tmp/mysql3357.sock
mysql8.0 -uroot -p<your-password> -S /tmp/mysql3306.sock
mysql -uroot -p<your-password>

四、发布前的整理建议

4.1 需要补充的说明

  • 安装包需要提前放到 /usr/local,这一点建议写成“环境准备”章节。
  • userdel -r mysql 这类卸载动作要写明风险,避免误删共享用户。
  • 默认密码不要直接发布,建议改成交互输入或环境变量。

五、完整脚本

以下为本文对应的完整脚本,便于直接复制复用。

5.1 mysql_single_instance_5.6-8.0_install_uninstall.sh

#!/bin/bash
##############################################################
# File Name: install_uninstall_mysql.sh
# Version: V1.2
# Author: zq
# Organization: www.zhang-qing.com
# Desc: 单实例MySQL版本管理脚本(支持5.6/5.7/8.0切换)
##############################################################

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

# 全局常量
MYSQL_BASE_DIR="/usr/local/mysql"
MYSQL_DATA_DIR="/data/mysql/data"
SOCKET_PATH="/tmp/mysql.sock"
SERVICE_NAME="mysqld"

# 预检查函数
precheck() {
    # 检查是否已存在运行中的实例
    if systemctl is-active "${SERVICE_NAME}" &>/dev/null; then
        echo -e "${RED}发现正在运行的MySQL服务,请先卸载当前版本!${NC}"
        return 1
    fi
    # 检查残留文件
    if [ -L "${MYSQL_BASE_DIR}" ] || [ -d "${MYSQL_DATA_DIR}" ]; then
        echo -e "${RED}发现残留的MySQL文件,请先清理!${NC}"
        return 1
    fi
    return 0
}

# 安装函数
install_mysql() {
    local version=$1
    local package_prefix=$2

    echo -e "${YELLOW}开始安装MySQL ${version}...${NC}"

    # 预检查
    if ! precheck; then
        return 1
    fi

    # 步骤1:检查安装包
    local pkg_file=$(ls /usr/local/${package_prefix}* 2>/dev/null | head -1)
    if [ -z "${pkg_file}" ]; then
        echo -e "${RED}未找到${package_prefix}开头的安装包${NC}"
        return 1
    fi

    # 步骤2:解压并创建软链接
    echo "解压安装包并创建软链接..."
    tar -xf "${pkg_file}" -C /usr/local
    local extracted_dir=$(tar tf "${pkg_file}" | head -1 | cut -d/ -f1)
    ln -sfn "/usr/local/${extracted_dir}" "${MYSQL_BASE_DIR}"

    # 步骤3:创建用户和目录
    echo "初始化系统环境..."
    id mysql &>/dev/null || useradd -r -s /sbin/nologin mysql
    mkdir -p "${MYSQL_DATA_DIR}" "/data/mysql/logs"
    chown -R mysql:mysql /data

    # 步骤4:初始化数据库
    echo "执行数据库初始化..."
    case $version in
        8*)
            "${MYSQL_BASE_DIR}/bin/mysqld" --initialize-insecure --user=mysql \
            --basedir="${MYSQL_BASE_DIR}" --datadir="${MYSQL_DATA_DIR}" >/dev/null 2>&1
            password_cmd="ALTER USER root@'localhost' IDENTIFIED BY '123456';"
            ;;
        5.7*)
            "${MYSQL_BASE_DIR}/bin/mysqld" --initialize-insecure --user=mysql \
            --basedir="${MYSQL_BASE_DIR}" --datadir="${MYSQL_DATA_DIR}" >/dev/null 2>&1
            password_cmd="UPDATE mysql.user SET authentication_string=PASSWORD('123456') WHERE user='root';"
            ;;
        5.6*)
            "${MYSQL_BASE_DIR}/scripts/mysql_install_db" --user=mysql \
            --basedir="${MYSQL_BASE_DIR}" --datadir="${MYSQL_DATA_DIR}" >/dev/null 2>&1
            password_cmd="SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123456');"
            ;;
    esac

    # 步骤5:创建配置文件
    echo "生成配置文件..."
    cat > /etc/my.cnf <<EOF
[mysql]
socket=${SOCKET_PATH}

[mysqld]
user=mysql
port=3306
socket=${SOCKET_PATH}
basedir=${MYSQL_BASE_DIR}
datadir=${MYSQL_DATA_DIR}
server_id=1
EOF

    # 步骤6:配置systemd服务
    echo "设置系统服务..."
    cat > /usr/lib/systemd/system/${SERVICE_NAME}.service <<EOF
[Unit]
Description=MySQL Server
After=network.target

[Service]
User=mysql
Group=mysql
ExecStart=${MYSQL_BASE_DIR}/bin/mysqld --defaults-file=/etc/my.cnf
ExecStop=${MYSQL_BASE_DIR}/bin/mysqladmin shutdown
LimitNOFILE=5000

[Install]
WantedBy=multi-user.target
EOF

    # 步骤7:启动服务
    systemctl daemon-reload
    if ! systemctl start mysqld; then
        echo -e "${RED}服务启动失败!${NC}"
        journalctl -u mysqld -n 20 --no-pager
        return 1
    fi

    # 新增socket文件等待逻辑
    echo -n "等待MySQL启动..."
    local timeout=30
    while [ ! -S "${SOCKET_PATH}" ] && [ $timeout -gt 0 ]; do
        sleep 1
        echo -n "."
        timeout=$((timeout-1))
    done
    echo

    if [ ! -S "${SOCKET_PATH}" ]; then
        echo -e "${RED}错误:等待socket文件超时(${SOCKET_PATH}${NC}"
        journalctl -u mysqld -n 20 --no-pager
        return 1
    fi
    # 步骤8:设置root密码
    echo "配置root账户..."
    local retries=3
    for ((i=1; i<=retries; i++)); do
        if "${MYSQL_BASE_DIR}/bin/mysql" -uroot -S "${SOCKET_PATH}" --connect-timeout=10 <<EOF
${password_cmd};
FLUSH PRIVILEGES;
EOF
        then
            break
        fi
        if [ $i -eq $retries ]; then
            echo -e "${RED}密码设置失败!请手动执行:${NC}"
            echo "mysql -uroot -S ${SOCKET_PATH}"
            return 1
        fi
        sleep 2
    done

    # 创建快捷命令
    ln -sf "${MYSQL_BASE_DIR}/bin/mysql" /usr/local/bin/mysql
    echo -e "${GREEN}MySQL ${version} 安装成功!${NC}"
}

# 卸载函数
uninstall_mysql() {
    echo -e "${YELLOW}开始卸载MySQL...${NC}"

    systemctl stop "${SERVICE_NAME}" 2>/dev/null
    systemctl disable "${SERVICE_NAME}" 2>/dev/null

    # 清理文件
    rm -rf "${MYSQL_DATA_DIR}" /etc/my.cnf
    find /usr/local -maxdepth 1 -type d -name "mysql-*" -exec rm -rf {} +
    rm -f "${MYSQL_BASE_DIR}" /usr/local/bin/mysql

    # 清理systemd配置
    rm -f "/usr/lib/systemd/system/${SERVICE_NAME}.service"
    systemctl daemon-reload

    echo -e "${GREEN}MySQL 卸载完成!${NC}"
}

# 菜单系统
main_menu() {
    while :; do
        clear
        echo -e "MySQL版本管理菜单"
        echo "1. 安装MySQL 8.0"
        echo "2. 安装MySQL 5.7"
        echo "3. 安装MySQL 5.6"
        echo "4. 卸载当前MySQL"
        echo "0. 退出"
        read -p "请选择: " choice

        case $choice in
            1) install_mysql "8.0" "mysql-8.0" ;;
            2) install_mysql "5.7" "mysql-5.7" ;;
            3) install_mysql "5.6" "mysql-5.6" ;;
            4) uninstall_mysql ;;
            0) exit 0 ;;
            *) echo -e "${RED}无效选项!${NC}"; sleep 1 ;;
        esac
        read -n 1 -p "按任意键继续..."
    done
}

# 执行入口
main_menu

5.2 mysql_multi_instance_5.6-8.0_install_uninstall.sh

#!/bin/bash
##############################################################
# File Name:install_uninstall_myqsl56_57_8.sh
# Version:V1.0
# Author:zq
# Organization:www.zhang-qing.com
# Desc: 二进制多实例MySQL版本管理脚本(支持5.6/5.7/8.0切换)
##############################################################

# 通用颜色设置
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m'

# 通用确认函数
confirm_operation() {
    read -p "是否继续?(y/n): " choice
    case "$choice" in
        y|Y) return 0 ;;
        *) echo "操作已取消"; return 1 ;;
    esac
}

# 安装函数
install_mysql() {
    local version=$1
    local package_prefix=$2
    local port=$3
    local version_suffix=$4
    local service_name="mysqld${port}"
    local base_dir="/usr/local/mysql${version_suffix}"
    local data_dir="/data/${port}/data"
    local socket_path="/tmp/mysql${port}.sock"

    echo -e "${YELLOW}开始安装MySQL ${version}...${NC}"

    # 步骤1:检查安装包
    local pkg_file=$(ls /usr/local/${package_prefix}* 2>/dev/null | head -1)
    if [ -z "${pkg_file}" ]; then
        echo -e "${RED}未找到${package_prefix}开头的安装包,请上传到/usr/local目录${NC}"
        return 1
    fi

    # 步骤2:解压安装包(保留目录结构)
    echo "解压安装包..."
    cd /usr/local && tar xf "${pkg_file}"
    local extracted_dir=$(tar tf "${pkg_file}" | head -1 | cut -d/ -f1)

    # 步骤3:创建软链接
    echo "创建软链接:${base_dir} -> ${extracted_dir}"
    ln -sf "/usr/local/${extracted_dir}" "${base_dir}"

    # 步骤4:创建用户和目录
    echo "创建用户和目录..."
    id mysql &> /dev/null || useradd -r -s /sbin/nologin mysql
    mkdir -p "${data_dir}" "/data/${port}/logs"
    chown -R mysql:mysql /data

    # 步骤5:初始化数据库
    echo "初始化数据库..."
    if [ -n "$(ls -A "${data_dir}")" ]; then
        echo "发现已有数据,清理目录..."
        rm -rf "${data_dir}"/*
    fi

    case $version in
        8*)
            "${base_dir}/bin/mysqld" --initialize-insecure --user=mysql \
            --basedir="${base_dir}" --datadir="${data_dir}" 2>/dev/null
            password_cmd="ALTER USER root@'localhost' IDENTIFIED BY '123456';"
            ;;
        5.7*)
            "${base_dir}/bin/mysqld" --initialize-insecure --user=mysql \
            --basedir="${base_dir}" --datadir="${data_dir}" 2>/dev/null
            password_cmd="UPDATE mysql.user SET authentication_string=PASSWORD('123456') WHERE user='root';"
            ;;
        5.6*)
            "${base_dir}/scripts/mysql_install_db" --user=mysql \
            --basedir="${base_dir}" --datadir="${data_dir}" 2>/dev/null
            password_cmd="SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123456');"
            ;;
    esac

    # 步骤6:创建配置文件
    echo "创建配置文件..."
    cat > "${data_dir}/my.cnf" <<EOF
[mysql]
socket=${socket_path}

[mysqld]
user=mysql
port=${port}
socket=${socket_path}
basedir=${base_dir}
datadir=${data_dir}
server_id=${port}
innodb_fast_shutdown=0
EOF

    # 步骤7:创建systemd服务
    echo "创建systemd服务..."
    cat > "/usr/lib/systemd/system/${service_name}.service" <<EOF
[Unit]
Description=MySQL ${version} Server
After=network.target

[Service]
User=mysql
Group=mysql
ExecStart=${base_dir}/bin/mysqld --defaults-file=${data_dir}/my.cnf
ExecStop=${base_dir}/bin/mysqladmin --defaults-file=${data_dir}/my.cnf shutdown
ExecReload=${base_dir}/bin/mysqladmin --defaults-file=${data_dir}/my.cnf reload
LimitNOFILE=5000

[Install]
WantedBy=multi-user.target
EOF

    # 步骤8:启动服务
    echo "启动服务..."
    systemctl daemon-reload
    if ! systemctl restart "${service_name}"; then
        echo -e "${RED}服务启动失败,请检查以下日志:${NC}"
        journalctl -u "${service_name}" -n 20 --no-pager
        return 1
    fi
    # 新增服务状态检查
    if ! systemctl is-active --quiet "${service_name}"; then
        echo -e "${RED}服务未处于运行状态,请检查日志${NC}"
        return 1
    fi

    # 新增等待socket文件生成的逻辑(最多等待30秒)
    echo "等待MySQL socket文件生成..."
    timeout=30
    while [ ! -S "${socket_path}" ] && [ $timeout -gt 0 ]; do
        sleep 1
        timeout=$((timeout-1))
    done

    if [ ! -S "${socket_path}" ]; then
        echo -e "${RED}错误:等待socket文件超时(${socket_path}${NC}"
        echo -e "${YELLOW}可能原因:\n1. MySQL启动失败\n2. 配置文件路径错误\n3. 权限问题${NC}"
        journalctl -u "${service_name}" -n 20 --no-pager
        return 1
    fi

    # 步骤9:设置密码
    echo "设置root密码..."
    retry_count=3
    for i in $(seq 1 $retry_count); do
        if "${base_dir}/bin/mysql" -uroot -S "${socket_path}" --connect-timeout=10 <<EOF
${password_cmd}
FLUSH PRIVILEGES;
EOF
    then
        break
    fi
    if [ $i -eq $retry_count ]; then
        echo -e "${RED}密码设置失败,请手动执行以下命令:${NC}"
        echo "${base_dir}/bin/mysql -uroot -S ${socket_path}"
        return 1
    fi
    done
    # 步骤10:创建版本化命令别名
    echo "创建全局命令链接..."
    ln -sf "${base_dir}/bin/mysql" "/usr/local/bin/mysql${version_suffix}"
    ln -sf "${base_dir}/bin/mysqldump" "/usr/local/bin/mysqldump${version_suffix}"
    ln -sf "${base_dir}/bin/mysqladmin" "/usr/local/bin/mysqladmin${version_suffix}"
    echo -e "${GREEN}MySQL ${version} 安装完成!${NC}"
    echo -e "连接信息:\n  命令: mysql${version_suffix}\n  Socket: ${socket_path}\n  Port: ${port}\n  密码: 123456"
}

# 卸载函数(安全增强版)
uninstall_mysql() {
    local port=$1
    local service_name="mysqld${port}"
    local data_dir="/data/${port}"

    echo -e "${YELLOW}开始卸载MySQL...${NC}"

    # 确认操作
    read -p "确认要卸载MySQL(端口:${port})?此操作不可逆!(y/n): " confirm
    [[ "$confirm" != "y" ]] && echo "操作已取消" && return

    # 步骤1:停止服务
    echo "停止服务..."
    systemctl stop "${service_name}" 2>/dev/null
    systemctl disable "${service_name}" 2>/dev/null

    # 步骤2:删除数据目录
    echo "删除数据目录..."
    [ -d "${data_dir}" ] && rm -rf "${data_dir}" && echo "删除 ${data_dir}"

    # 步骤3:删除用户(安全判断)
    if id mysql &>/dev/null; then
        if ! userdel -r mysql 2>/dev/null; then
            echo -e "${RED}删除mysql用户失败,请手动检查${NC}"
        fi
    fi

    # 步骤4:精确清理文件
    echo "清理残留文件..."
    find /usr/local -maxdepth 1 -type l -name "mysql*" -delete
    find /usr/local -maxdepth 1 -type d -name "mysql-*" -exec rm -rf {} +
    rm -f "/usr/lib/systemd/system/${service_name}.service"
    systemctl daemon-reload

    # 步骤5:删除版本化命令别名
    local version_suffix
    case $port in
        3306) version_suffix="8.0" ;;
        3357) version_suffix="5.7" ;;
        3356) version_suffix="5.6" ;;
    esac

    echo "删除命令别名..."
    rm -f "/usr/local/bin/mysql${version_suffix}" \
          "/usr/local/bin/mysqldump${version_suffix}" \
          "/usr/local/bin/mysqladmin${version_suffix}" 2>/dev/null

    echo -e "${GREEN}MySQL(端口:${port})卸载完成!${NC}"
}

# 主菜单
main_menu() {
    while true; do
        clear
        echo "======== MySQL管理菜单 ========"
        echo "1. 安装MySQL"
        echo "2. 卸载MySQL"
        echo "0. 退出"
        read -p "请输入选择: " main_choice

        case $main_choice in
            1) install_submenu ;;
            2) uninstall_submenu ;;
            0) exit 0 ;;
            *) echo -e "${RED}无效的选项,请重新输入${NC}"; sleep 1 ;;
        esac
    done
}

# 安装子菜单
install_submenu() {
    while true; do
        clear
        echo "-------- 安装MySQL版本 --------"
        echo "1. MySQL 8.0(端口:3306)"
        echo "2. MySQL 5.7(端口:3357)"
        echo "3. MySQL 5.6(端口:3356)"
        echo "0. 返回主菜单"
        read -p "请选择版本: " ver_choice

        case $ver_choice in
            1) install_mysql "8.0" "mysql-8.0" 3306 "8.0" ;;
            2) install_mysql "5.7" "mysql-5.7" 3357 "5.7" ;;
            3) install_mysql "5.6" "mysql-5.6" 3356 "5.6" ;;
            0) return ;;
            *) echo -e "${RED}无效的版本选择${NC}"; sleep 1 ;;
        esac
        if [ $? -eq 0 ]; then
            read -p "按回车键返回菜单..."
            break
        fi
    done
}

# 卸载子菜单
uninstall_submenu() {
    while true; do
        clear
        echo "-------- 卸载MySQL版本 --------"
        echo "1. MySQL 8.0(端口:3306)"
        echo "2. MySQL 5.7(端口:3357)"
        echo "3. MySQL 5.6(端口:3356)"
        echo "0. 返回主菜单"
        read -p "请选择版本: " ver_choice

        case $ver_choice in
            1) uninstall_mysql 3306 ;;
            2) uninstall_mysql 3357 ;;
            3) uninstall_mysql 3356 ;;
            0) return ;;
            *) echo -e "${RED}无效的版本选择${NC}"; sleep 1 ;;
        esac
        read -p "按回车键返回菜单..."
    done
}

# 脚本入口
main_menu