1. 脚本概述

1.1 脚本是什么?

这是一个用于自动化安装Oracle Database 11g Release 2 (11.2.0.4)的Bash脚本。脚本采用静默安装模式,无需人工交互,通过预设的响应文件自动完成整个Oracle数据库的部署过程。

1.2 脚本的功能特性

本脚本具有以下核心功能:

  1. 完全自动化安装:从环境检查到数据库创建,全流程自动完成

  2. 参数化配置:所有安装参数集中配置,易于修改和复用

  3. 多模式支持:支持完整安装、只安装软件、只创建数据库等多种模式

  4. 智能清理功能:彻底清理Oracle环境残留,解决重复安装问题

  5. 健壮的错误处理:完善的错误检测和恢复机制

  6. 详细的日志记录:所有操作步骤都有详细日志记录

  7. 环境验证:安装前后进行系统环境和Oracle状态验证

1.3 解决的核心问题

  1. 传统安装复杂:传统Oracle安装需要图形界面和大量手动配置

  2. 重复安装冲突:解决Oracle清理不彻底导致的重复安装失败问题

  3. 环境一致性:确保在不同环境中安装的Oracle配置一致

  4. 安装效率:将数小时的手动安装缩短到约30分钟

2. 脚本功能详解

2.1 支持的安装模式

 
模式命令功能描述
完整安装 sh ora_install.sh 从零开始完整安装Oracle软件并创建数据库
环境检查 sh ora_install.sh --check 只检查系统环境,不进行安装
只安装软件 sh ora_install.sh --software-only 只安装Oracle软件,不创建数据库
只创建数据库 sh ora_install.sh --database-only 只创建数据库(假设软件已安装)
清理卸载 sh ora_install.sh --clean 彻底清理卸载Oracle

2.2 安装流程

脚本的执行流程如下:

deepseek_mermaid_20251208_ea7cd5

2.3 关键技术特性

2.3.1 彻底的环境清理

脚本特别解决了Oracle重复安装时常见的问题:

  1. 进程清理:停止所有Oracle相关进程,包括数据库实例、监听器等

  2. IPC资源清理:清理共享内存、信号量、消息队列等系统资源

  3. 文件清理:删除所有Oracle相关目录和配置文件

  4. 用户清理:删除Oracle用户和相关用户组

2.3.2 智能的状态管理

  • 步骤跟踪:记录每个步骤的完成状态,支持断点续装

  • 依赖检查:自动检查并安装缺失的系统依赖包

  • 环境验证:安装前后验证系统环境是否符合要求

  • 日志记录:详细记录安装过程,便于问题排查

2.3.3 安全的进程管理

脚本采用安全的进程管理策略,避免杀死自身或系统关键进程:

  1. 进程识别:精确识别Oracle相关进程,避免误杀

  2. 安全终止:先尝试正常终止,再强制终止

  3. 进程排除:排除当前脚本进程和系统关键进程

3. 使用前提

3.1 系统要求

  1. 操作系统:CentOS/RHEL 6.x 或 7.x(64位)

  2. 内存:建议至少2GB RAM

  3. 磁盘空间:建议至少10GB可用空间

  4. 权限:必须以root用户执行

3.2 准备工作

  1. 下载Oracle安装包:

    • p13390677_112040_Linux-x86-64_1of7.zip

    • p13390677_112040_Linux-x86-64_2of7.zip

  2. 放置安装包:

    text
    /data/dba/oracle/p13390677_112040_Linux-x86-64_1of7.zip
    /data/dba/oracle/p13390677_112040_Linux-x86-64_2of7.zip
  3. 网络配置:确保主机名和IP地址正确配置

4. 配置参数说明

脚本的主要配置参数集中在脚本开头的配置区:

bash
# 安装基础路径
readonly INSTALL_BASE_DIR="/data/u01"
readonly DATA_BASE_DIR="/data/u02"
readonly SOFTWARE_BASE_DIR="/data/dba/oracle"
readonly LOG_BASE_DIR="/var/log"

# Oracle安装参数
readonly ORACLE_VERSION="11.2.0.4"
readonly ORACLE_SID="caiwu"
readonly ORACLE_CHARSET="ZHS16GBK"
readonly ORACLE_MEMORY_PERCENTAGE="70"

# 用户和组配置
readonly ORACLE_USER="oracle"
readonly ORACLE_PASSWORD="oracle"
readonly ORACLE_PRIMARY_GROUP="oinstall"
readonly ORACLE_DBA_GROUP="dba"
readonly ORACLE_OPER_GROUP="oper"

# 数据库参数
readonly SYS_PASSWORD="oracle"
readonly SYSTEM_PASSWORD="oracle"

用户可以根据实际需求修改这些参数。

5. 使用示例

5.1 完整安装示例

bash
# 1. 下载Oracle安装包到指定目录
mkdir -p /data/dba/oracle
# 将p13390677_112040_Linux-x86-64_1of7.zip和2of7.zip放置到此目录

# 2. 给脚本执行权限
chmod +x ora_install.sh

# 3. 执行完整安装
sh ora_install.sh

5.2 分阶段安装示例

bash
# 1. 先检查环境
sh ora_install.sh --check

# 2. 只安装Oracle软件
sh ora_install.sh --software-only

# 3. 只创建数据库
sh ora_install.sh --database-only

5.3 清理和重新安装示例

bash
# 1. 清理现有的Oracle安装
sh ora_install.sh --clean

# 2. 重新完整安装
sh ora_install.sh

6. 故障排查

6.1 常见问题

  1. 安装包找不到:确保安装包路径正确,文件名正确

  2. 权限不足:确保以root用户执行

  3. 端口被占用:检查1521端口是否被其他程序占用

  4. 磁盘空间不足:检查/data目录是否有足够空间

6.2 日志文件

脚本会生成详细的日志文件:

  • 安装日志:/var/log/oracle_install_YYYYMMDD_HHMMSS/install.log

  • 错误日志:/var/log/oracle_install_YYYYMMDD_HHMMSS/error.log

6.3 手动检查

如果安装失败,可以手动检查:

bash
# 检查Oracle进程
ps -ef | grep ora_

# 检查监听器状态
lsnrctl status

# 检查数据库状态
sqlplus / as sysdba <<< "select status from v\$instance;"

# 检查共享内存
ipcs -m | grep oracle

7. 脚本优势总结

  1. 高效性:将复杂的Oracle安装过程自动化,节省大量时间

  2. 可靠性:经过多次测试验证,确保安装成功率高

  3. 灵活性:支持多种安装模式,适应不同场景需求

  4. 易用性:配置简单,执行方便,无需专业Oracle DBA知识

  5. 可维护性:脚本结构清晰,便于修改和维护

此脚本特别适用于需要频繁部署Oracle环境的测试环境、开发环境和生产环境,能够显著提高部署效率和环境一致性。

8. 脚本内容

[root@zb-yunweitest-mysql-204-200 oracle]# cat ora_install.sh 
#!/bin/bash
# ============================================================================
# Oracle 11.2 静默安装脚本重构增强版
# 版本: 4.0
# 作者: Oracle自动化脚本重构
# 特点: 完全参数化,支持多种安装模式,带重复配置检查
# ============================================================================

# 设置脚本执行选项
set -o errexit          # 遇到错误时退出脚本
set -o nounset          # 遇到未定义变量时退出脚本
set -o pipefail         # 管道中任意命令失败时退出脚本

# ============================================================================
# 配置参数区 - 可根据需要修改这些变量
# ============================================================================

# 安装基础路径
readonly INSTALL_BASE_DIR="/data/u01"
readonly DATA_BASE_DIR="/data/u02"
readonly SOFTWARE_BASE_DIR="/data/dba/oracle"
readonly LOG_BASE_DIR="/var/log"

# Oracle安装参数
readonly ORACLE_VERSION="11.2.0.4"
readonly ORACLE_SID="caiwu"
readonly ORACLE_CHARSET="ZHS16GBK"
readonly ORACLE_MEMORY_PERCENTAGE="70"
readonly ORACLE_BASE="${INSTALL_BASE_DIR}/app/oracle"
readonly ORACLE_HOME="${ORACLE_BASE}/product/${ORACLE_VERSION}/db_1"
readonly ORACLE_INVENTORY="${INSTALL_BASE_DIR}/app/oraInventory"
readonly ORACLE_DATA_DIR="${DATA_BASE_DIR}/${ORACLE_SID}"
readonly ORACLE_SOFTWARE_DIR="${SOFTWARE_BASE_DIR}/software"
readonly ORACLE_General_Purpose="${ORACLE_HOME}/assistants/dbca/templates/General_Purpose.dbc"

# 用户和组配置
readonly ORACLE_USER="oracle"
readonly ORACLE_PASSWORD="oracle"
readonly ORACLE_PRIMARY_GROUP="oinstall"
readonly ORACLE_DBA_GROUP="dba"
readonly ORACLE_OPER_GROUP="oper"

# 安装包配置
readonly ORACLE_ZIP_FILES=(
    "/data/dba/oracle/p13390677_112040_Linux-x86-64_1of7.zip"
    "/data/dba/oracle/p13390677_112040_Linux-x86-64_2of7.zip"
)

# 数据库参数
readonly SYS_PASSWORD="oracle"
readonly SYSTEM_PASSWORD="oracle"

# 系统变量
readonly HOSTNAME=$(hostname)
readonly IP_ADDRESS=$(hostname -I | awk '{print $1}')

# 状态文件
readonly STATE_TIME="$(date +%Y%m%d_%H%M%S)"
readonly STATE_DIR="/tmp/oracle_install_state_$STATE_TIME"
readonly LOG_DIR="${LOG_BASE_DIR}/oracle_install_$STATE_TIME"
readonly INSTALL_LOG="${LOG_DIR}/install.log"
readonly ERROR_LOG="${LOG_DIR}/error.log"

# 颜色输出
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 全局变量
INSTALL_MODE="full"  # 默认安装模式:full, check, software-only, database-only, clean

# ============================================================================
# 工具函数
# ============================================================================

# 打印信息
print_info() {
    echo -e "${GREEN}[INFO] $1${NC}"
}

print_warn() {
    echo -e "${YELLOW}[WARN] $1${NC}"
}

print_error() {
    echo -e "${RED}[ERROR] $1${NC}"
}

print_step() {
    echo -e "${BLUE}[STEP] $1${NC}"
}

# 检查root权限
check_root() {
    if [[ $EUID -ne 0 ]]; then
        print_error "此脚本必须以root用户运行"
        exit 1
    fi
}

# 显示使用方法
show_usage() {
    cat << EOF
用法: $0 [选项]

选项:
  --check          只检查安装环境,不进行安装
  --software-only  只安装Oracle软件,不创建数据库
  --database-only  只创建数据库(假设软件已安装)
  --clean          清理卸载Oracle
  --help           显示此帮助信息

示例:
  $0 --check              # 只检查环境
  $0 --software-only      # 只安装软件
  $0 --database-only      # 只创建数据库
  $0 --clean              # 清理卸载
  $0                      # 完整安装

EOF
    exit 0
}

# 解析命令行参数
parse_arguments() {
    if [[ $# -eq 0 ]]; then
        INSTALL_MODE="full"
        return
    fi
    
    case "$1" in
        --check)
            INSTALL_MODE="check"
            ;;
        --software-only)
            INSTALL_MODE="software-only"
            ;;
        --database-only)
            INSTALL_MODE="database-only"
            ;;
        --clean)
            INSTALL_MODE="clean"
            ;;
        --help|-h)
            show_usage
            ;;
        *)
            print_error "未知参数: $1"
            show_usage
            ;;
    esac
}

# ============================================================================
# 核心函数库
# ============================================================================

# 初始化安装环境
init_environment() {
    echo "================================================================"
    echo "开始Oracle 11.2.0.4静默安装"
    echo "================================================================"
    echo "安装模式:           ${INSTALL_MODE}"
    echo "主机名:             ${HOSTNAME}"
    echo "IP地址:             ${IP_ADDRESS}"
    echo "Oracle SID:         ${ORACLE_SID}"
    echo "Oracle基目录:       ${ORACLE_BASE}"
    echo "数据目录:           ${ORACLE_DATA_DIR}"
    echo "安装组件的状态目录:${STATE_DIR}"
    echo "安装日志文件:      ${INSTALL_LOG}"
    echo "安装错误日志文件:  ${ERROR_LOG}"
    echo "================================================================"
    
    # 创建必要的目录
    mkdir -p "${LOG_DIR}"
    mkdir -p "${STATE_DIR}"
    
    # 创建日志文件
    touch "${INSTALL_LOG}" "${ERROR_LOG}"
    
    print_info "初始化完成"
    echo "$(date): 初始化完成" | tee -a "${INSTALL_LOG}"
}

# 记录步骤完成状态
mark_step_completed() {
    local step_name="$1"
    touch "${STATE_DIR}/${step_name}.completed"
    echo "$(date): 步骤 ${step_name} 完成" | tee -a "${INSTALL_LOG}"
}

# 检查步骤是否已完成
check_step_completed() {
    local step_name="$1"
    if [[ -f "${STATE_DIR}/${step_name}.completed" ]]; then
        echo "$(date): 步骤 ${step_name} 已跳过(已完成)" | tee -a "${INSTALL_LOG}"
        return 0
    fi
    return 1
}

# ============================================================================
# 检查函数库
# ============================================================================

# 检查操作系统版本
check_os_version() {
    print_step "检查操作系统版本..."
    
    local os_release="/etc/redhat-release"
    if [[ ! -f "$os_release" ]]; then
        os_release="/etc/os-release"
    fi
    
    if [[ -f "$os_release" ]]; then
        echo "操作系统信息:"
        cat "$os_release" | head -5
    else
        print_warn "无法确定操作系统版本"
    fi
    
    # 检查是否是64位系统
    if [[ $(uname -m) != "x86_64" ]]; then
        print_error "需要64位操作系统"
        exit 1
    fi
    
    print_info "操作系统检查完成"
}

# 检查磁盘空间
check_disk_space() {
    print_step "检查磁盘空间..."
    
    local required_space=10240  # 10GB in MB
    local available_space
    
    # 检查根目录
    available_space=$(df -m / | tail -1 | awk '{print $4}')
    echo "根目录可用空间: ${available_space}MB"
    
    if [[ $available_space -lt $required_space ]]; then
        print_warn "根目录空间不足,建议至少10GB"
    fi
    
    # 检查安装目录
    if [[ -d "$INSTALL_BASE_DIR" ]]; then
        available_space=$(df -m "$INSTALL_BASE_DIR" | tail -1 | awk '{print $4}')
        echo "安装目录可用空间: ${available_space}MB"
    fi
    
    print_info "磁盘空间检查完成"
}

# 检查内存
check_memory() {
    print_step "检查内存..."
    
    local total_mem=$(grep MemTotal /proc/meminfo | awk '{print $2}')
    local mem_gb=$((total_mem / 1024 / 1024))
    
    echo "总内存: ${total_mem}KB (约${mem_gb}GB)"
    
    if [[ $total_mem -lt 2097152 ]]; then  # 小于2GB
        print_warn "内存较小,建议至少2GB"
    fi
    
    print_info "内存检查完成"
}

# 检查Oracle安装文件
check_oracle_software() {
    print_step "检查Oracle安装文件..."
    
    local missing_files=()
    for zip_file in "${ORACLE_ZIP_FILES[@]}"; do
        if [[ ! -f "$zip_file" ]]; then
            missing_files+=("$zip_file")
            print_error "找不到安装文件: $zip_file"
        else
            print_info "找到安装文件: $zip_file"
            local file_size=$(du -h "$zip_file" | awk '{print $1}')
            echo "  文件大小: $file_size"
        fi
    done
    
    if [[ ${#missing_files[@]} -gt 0 ]]; then
        print_error "请将以下文件放置到指定位置:"
        for file in "${missing_files[@]}"; do
            echo "  $file"
        done
        return 1
    fi
    
    print_info "Oracle安装文件检查完成"
    return 0
}

# 检查端口占用
check_ports() {
    print_step "检查端口占用..."
    
    local ports=(1521 5500)
    
    for port in "${ports[@]}"; do
        if netstat -tlnp 2>/dev/null | grep ":$port " > /dev/null; then
            print_warn "端口 $port 已被占用"
            netstat -tlnp | grep ":$port "
        else
            print_info "端口 $port 可用"
        fi
    done
}

# 检查依赖包
check_dependencies() {
    print_step "检查依赖包..."
    
    local required_packages=(
        "binutils" "compat-libcap1" "compat-libstdc++-33"
        "gcc" "gcc-c++" "glibc" "glibc-devel" "ksh"
        "libgcc" "libstdc++" "libstdc++-devel" "libaio"
        "libaio-devel" "libXext" "libXtst" "libX11"
        "libXau" "libxcb" "libXi" "make" "sysstat"
        "unzip" "unixODBC" "unixODBC-devel"
    )
    
    local missing_packages=()
    
    for pkg in "${required_packages[@]}"; do
        if ! rpm -q "$pkg" &>/dev/null; then
            missing_packages+=("$pkg")
            print_warn "缺少包: $pkg"
        else
            print_info "已安装: $pkg"
        fi
    done
    
    if [[ ${#missing_packages[@]} -gt 0 ]]; then
        echo "缺少的依赖包:"
        for pkg in "${missing_packages[@]}"; do
            echo "  $pkg"
        done
        print_warn "可以通过运行完整安装自动安装这些包"
    else
        print_info "所有依赖包已安装"
    fi
}

# 综合环境检查
check_environment() {
    print_step "开始环境检查..."
    
    check_root
    check_os_version
    check_disk_space
    check_memory
    check_oracle_software
    check_ports
    check_dependencies
    
    print_step "环境检查完成"
    echo ""
    echo "检查结果摘要:"
    echo "  操作系统: 通过"
    echo "  磁盘空间: 通过"
    echo "  内存: 通过"
    echo "  安装文件: 通过"
    echo "  端口: 通过"
    echo "  依赖包: 部分可能需要安装"
    echo ""
    echo "可以运行完整安装或使用 '--software-only' 开始安装软件"
}

# ============================================================================
# 安装函数库
# ============================================================================

# 安装并检查依赖包
install_dependencies() {
    if check_step_completed "install_dependencies"; then
        return 0
    fi
    
    print_step "开始安装依赖包..."
    
    # 基本依赖包
    local base_packages=(
        "binutils" "compat-libcap1" "compat-libstdc++-33"
        "gcc" "gcc-c++" "glibc" "glibc-devel" "ksh"
        "libgcc" "libstdc++" "libstdc++-devel" "libaio"
        "libaio-devel" "libXext" "libXtst" "libX11"
        "libXau" "libxcb" "libXi" "make" "sysstat"
        "unzip" "unixODBC" "unixODBC-devel"
    )
    
    # 检查并安装缺失的包
    for pkg in "${base_packages[@]}"; do
        if ! rpm -q "$pkg" &>/dev/null; then
            echo "$(date): 安装包: $pkg" | tee -a "${INSTALL_LOG}"
            yum -y install "$pkg" >> "${INSTALL_LOG}" 2>&1 || {
                echo "$(date): 警告: 包 $pkg 安装失败" | tee -a "${INSTALL_LOG}"
            }
        else
            echo "$(date): 包 $pkg 已安装" | tee -a "${INSTALL_LOG}"
        fi
    done
    
    mark_step_completed "install_dependencies"
    print_info "依赖包安装完成"
}

# 清理共享内存和信号量
clean_oracle_ipc() {
    print_step "清理Oracle共享内存和信号量..."
    
    # 1. 清理共享内存
    echo "检查Oracle共享内存段..."
    local shm_segments=$(ipcs -m | grep -w oracle | awk '{print $2}')
    
    if [[ -n "$shm_segments" ]]; then
        print_info "找到Oracle共享内存段,正在清理..."
        for shm_id in $shm_segments; do
            print_info "删除共享内存段: $shm_id"
            ipcrm -m "$shm_id" 2>/dev/null || true
        done
    else
        print_info "未找到Oracle共享内存段"
    fi
    
    # 2. 清理信号量
    echo "检查Oracle信号量..."
    local sem_ids=$(ipcs -s | grep -w oracle | awk '{print $2}')
    
    if [[ -n "$sem_ids" ]]; then
        print_info "找到Oracle信号量,正在清理..."
        for sem_id in $sem_ids; do
            print_info "删除信号量: $sem_id"
            ipcrm -s "$sem_id" 2>/dev/null || true
        done
    else
        print_info "未找到Oracle信号量"
    fi
    
    # 3. 清理消息队列
    echo "检查Oracle消息队列..."
    local msg_ids=$(ipcs -q | grep -w oracle | awk '{print $2}')
    
    if [[ -n "$msg_ids" ]]; then
        print_info "找到Oracle消息队列,正在清理..."
        for msg_id in $msg_ids; do
            print_info "删除消息队列: $msg_id"
            ipcrm -q "$msg_id" 2>/dev/null || true
        done
    else
        print_info "未找到Oracle消息队列"
    fi
    
    # 4. 清理/dev/shm中的Oracle文件
    echo "检查/dev/shm中的Oracle文件..."
    if [[ -d "/dev/shm" ]]; then
        local shm_files=$(ls -la /dev/shm | grep -E "(ora_|.ora_|sem\.)" | awk '{print $9}')
        if [[ -n "$shm_files" ]]; then
            print_info "清理/dev/shm中的Oracle文件..."
            for file in $shm_files; do
                if [[ -f "/dev/shm/$file" ]]; then
                    print_info "删除: /dev/shm/$file"
                    rm -f "/dev/shm/$file"
                fi
            done
        fi
    fi
    
    print_info "IPC资源清理完成"
}

# 检查并清理所有Oracle进程
force_kill_oracle() {
    print_step "强制清理所有Oracle相关进程..."
    
    # 1. 停止监听器
    if [[ -f "${ORACLE_HOME}/bin/lsnrctl" ]]; then
        print_info "停止监听器..."
        su - "${ORACLE_USER}" -c "
            export ORACLE_HOME=${ORACLE_HOME}
            ${ORACLE_HOME}/bin/lsnrctl stop 2>/dev/null || true
        " 2>/dev/null || true
    fi
    
    # 2. 停止数据库
    if [[ -f "${ORACLE_HOME}/bin/sqlplus" ]]; then
        print_info "停止数据库..."
        su - "${ORACLE_USER}" -c "
            export ORACLE_HOME=${ORACLE_HOME}
            export ORACLE_SID=${ORACLE_SID}
            echo 'shutdown abort;' | ${ORACLE_HOME}/bin/sqlplus -S / as sysdba 2>/dev/null || true
        " 2>/dev/null || true
    fi
    
    # 3. 安全的杀死Oracle进程
    print_info "安全地清理Oracle进程..."
    
    # 查找Oracle后台进程
    ps -ef | while read -r line; do
        # 跳过标题行
        if [[ "$line" == *"PID"* ]]; then
            continue
        fi
        
        local pid=$(echo "$line" | awk '{print $2}')
        local user=$(echo "$line" | awk '{print $1}')
        local command=$(echo "$line" | awk '{$1=$2=$3=$4=$5=$6=$7=""; print $0}')
        
        # 只处理oracle用户的进程
        if [[ "$user" == "$ORACLE_USER" ]] || [[ "$user" == "oracle" ]]; then
            # 检查是否是Oracle相关进程
            if echo "$command" | grep -qE "(ora_|asm_|ocssd|diskmon|tnslsnr)"; then
                safe_kill_process "$pid" 15  # 先尝试正常终止
                sleep 0.5
                safe_kill_process "$pid" 9   # 再强制终止
            fi
        fi
    done
    
    # 4. 额外清理:确保没有残留的Oracle进程
    print_info "检查是否有残留的Oracle进程..."
    
    # 等待一会儿让进程完全终止
    sleep 2
    
    # 再次检查并强制清理
    local remaining_processes=$(ps -u "$ORACLE_USER" -o pid= 2>/dev/null | grep -v "^$$\$")
    if [[ -n "$remaining_processes" ]]; then
        print_info "仍有进程残留,强制清理..."
        for pid in $remaining_processes; do
            safe_kill_process "$pid" 9
        done
    fi
    
    # 等待进程完全结束
    sleep 1
    
    print_info "进程清理完成"
}

# 停止Oracle用户的所有进程
stop_oracle_processes() {
    print_step "检查Oracle用户进程..."
    
    # 先强制清理所有Oracle进程
    force_kill_oracle
    
    # 检查是否有oracle用户的进程
    if pgrep -u "$ORACLE_USER" > /dev/null 2>&1; then
        print_info "找到Oracle用户进程,正在停止..."
        
        # 尝试优雅停止
        pkill -u "$ORACLE_USER"
        sleep 2
        
        # 如果仍有进程,强制停止
        if pgrep -u "$ORACLE_USER" > /dev/null 2>&1; then
            print_warn "仍有进程运行,强制停止..."
            pkill -9 -u "$ORACLE_USER"
            sleep 1
        fi
        
        # 最终检查
        if pgrep -u "$ORACLE_USER" > /dev/null 2>&1; then
            print_error "无法停止所有Oracle进程,请手动检查"
            echo "运行以下命令查看进程:ps -ef | grep $ORACLE_USER"
            return 1
        else
            print_info "所有Oracle进程已停止"
        fi
    else
        print_info "未找到Oracle用户进程"
    fi
    
    # 清理IPC资源
    clean_oracle_ipc
    
    return 0
}

# 删除Oracle用户
delete_oracle_user() {
    print_step "检查用户 $ORACLE_USER 是否存在..."
    
    if id "$ORACLE_USER" >/dev/null 2>&1; then
        print_info "删除用户 $ORACLE_USER..."
        
        # 先删除用户的主目录
        if [[ -d "/home/$ORACLE_USER" ]]; then
            rm -rf "/home/$ORACLE_USER"
            print_info "已删除目录 /home/$ORACLE_USER"
        fi
        
        # 删除用户
        userdel "$ORACLE_USER"
        
        if [[ $? -eq 0 ]]; then
            print_info "用户 $ORACLE_USER 已删除"
        else
            print_warn "删除用户 $ORACLE_USER 失败"
        fi
    else
        print_info "用户 $ORACLE_USER 不存在"
    fi
}

# 删除Oracle相关组
delete_oracle_groups() {
    local groups=("$ORACLE_DBA_GROUP" "$ORACLE_OPER_GROUP" "$ORACLE_PRIMARY_GROUP")
    
    for group in "${groups[@]}"; do
        print_step "检查组 $group 是否存在..."
        
        if getent group "$group" >/dev/null 2>&1; then
            print_info "删除组 $group..."
            groupdel "$group"
            
            if [[ $? -eq 0 ]]; then
                print_info "组 $group 已删除"
            else
                print_warn "删除组 $group 失败"
            fi
        else
            print_info "组 $group 不存在"
        fi
    done
}

# 清理安装软件、数据目录、/tmp目录下的Oracle临时文件
clean_tmp_directories() {
    print_step "清理/tmp目录下的Oracle临时文件..."
    
    local tmp_dirs=(
        "/tmp/CVU_11.2.0.4.0_oracle"
        "/tmp/dbca"
        "/tmp/hsperfdata_oracle"
        "/tmp/.oracle"
        "/tmp/CVU*"
        "$INSTALL_BASE_DIR"
        "$DATA_BASE_DIR"
        "$SOFTWARE_BASE_DIR/software"
        "/etc/oratab"
        "/etc/oraInst.loc"
    )
    
    for dir in "${tmp_dirs[@]}"; do
        # 使用find处理通配符
        if [[ "$dir" == *"*"* ]]; then
            for expanded_dir in $dir; do
                if [[ -d "$expanded_dir" || -f "$expanded_dir" ]]; then
                    print_info "删除 $expanded_dir..."
                    rm -rf "$expanded_dir"
                fi
            done
        elif [[ -d "$dir" || -f "$dir" ]]; then
            print_info "删除 $dir..."
            rm -rf "$dir"
        fi
    done
    
    print_info "装软件、数据目录、/tmp目录清理完成"
}

# 清理安装
clean_installation() {
    print_step "开始清理Oracle安装..."
    
    # 确认操作
    read -p "确认要清理卸载Oracle吗?(yes/no): " confirm
    if [[ "${confirm}" != "yes" ]]; then
        print_info "用户取消清理操作"
        return 0
    fi
    
    # 停止进程
    stop_oracle_processes
    
    # 删除用户和组
    delete_oracle_user
    delete_oracle_groups
    
    # 清理目录
    clean_tmp_directories
    
    # 清理环境变量
    local bash_profile="/home/${ORACLE_USER}/.bash_profile"
    if [[ -f "$bash_profile" ]]; then
        print_step "清理环境变量..."
        sed -i '/# Oracle环境变量/,/^[^#]/d' "$bash_profile" 2>/dev/null
        sed -i '/export ORACLE_/d' "$bash_profile" 2>/dev/null
    fi
    
    print_info "Oracle清理完成"
}

# 创建Oracle用户和组
create_oracle_user() {
    if check_step_completed "create_oracle_user"; then
        return 0
    fi
    
    print_step "创建Oracle用户和组..."
    
    # 检查并创建组
    if ! getent group "${ORACLE_PRIMARY_GROUP}" >/dev/null; then
        groupadd "${ORACLE_PRIMARY_GROUP}"
        print_info "创建组: ${ORACLE_PRIMARY_GROUP}"
    fi
    
    if ! getent group "${ORACLE_DBA_GROUP}" >/dev/null; then
        groupadd "${ORACLE_DBA_GROUP}"
        print_info "创建组: ${ORACLE_DBA_GROUP}"
    fi
    
    if ! getent group "${ORACLE_OPER_GROUP}" >/dev/null; then
        groupadd "${ORACLE_OPER_GROUP}"
        print_info "创建组: ${ORACLE_OPER_GROUP}"
    fi
    
    # 检查并创建用户
    if ! id "${ORACLE_USER}" >/dev/null 2>&1; then
        useradd -g "${ORACLE_PRIMARY_GROUP}" \
                -G "${ORACLE_DBA_GROUP},${ORACLE_OPER_GROUP}" \
                "${ORACLE_USER}"
        echo "${ORACLE_USER}:${ORACLE_PASSWORD}" | chpasswd
        print_info "创建用户: ${ORACLE_USER}"
    else
        print_info "用户 ${ORACLE_USER} 已存在"
    fi
    
    mark_step_completed "create_oracle_user"
}

# 配置内核参数
configure_kernel_parameters() {
    if check_step_completed "configure_kernel_parameters"; then
        return 0
    fi
    
    print_step "配置内核参数..."
    
    # 检查是否已配置
    local kernel_params_configured=false
    if grep -q "Oracle内核参数配置" /etc/sysctl.conf; then
        print_info "内核参数已配置,跳过"
        kernel_params_configured=true
    fi
    
    if [[ "$kernel_params_configured" == "false" ]]; then
        # 计算共享内存大小
        local total_mem_kb=$(grep MemTotal /proc/meminfo | awk '{print $2}')
        local shmmax=$((total_mem_kb * 1024 * 80 / 100))  # 80% of total memory
        local shmall=$((shmmax / 4096))
        
        cat >> /etc/sysctl.conf << EOF

# Oracle内核参数配置
fs.aio-max-nr = 1048576
fs.file-max = 6815744
kernel.shmall = ${shmall}
kernel.shmmax = ${shmmax}
kernel.shmmni = 4096
kernel.sem = 250 32000 100 128
net.ipv4.ip_local_port_range = 9000 65500
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048576
EOF
        
        print_info "内核参数配置已写入 /etc/sysctl.conf"
    fi
    
    # 应用内核参数
    sysctl -p >> "${INSTALL_LOG}" 2>&1
    print_info "内核参数已应用"
    
    mark_step_completed "configure_kernel_parameters"
}

# 配置用户资源限制
configure_user_limits() {
    if check_step_completed "configure_user_limits"; then
        return 0
    fi
    
    print_step "配置用户资源限制..."
    
    # 检查是否已配置
    if ! grep -q "Oracle用户资源限制" /etc/security/limits.conf; then
        cat >> /etc/security/limits.conf << EOF

# Oracle用户资源限制
${ORACLE_USER} soft nproc 2047
${ORACLE_USER} hard nproc 16384
${ORACLE_USER} soft nofile 1024
${ORACLE_USER} hard nofile 65536
${ORACLE_USER} soft stack 10240
EOF
        print_info "用户资源限制已配置"
    else
        print_info "用户资源限制已存在,跳过"
    fi
    
    # 配置pam.d
    if ! grep -q "pam_limits.so" /etc/pam.d/login; then
        echo "session required pam_limits.so" >> /etc/pam.d/login
    fi
    
    mark_step_completed "configure_user_limits"
}

# 创建Oracle目录结构
create_oracle_directories() {
    if check_step_completed "create_oracle_directories"; then
        return 0
    fi
    
    print_step "创建Oracle目录结构..."
    
    # 创建主目录
    local dirs=(
        "${INSTALL_BASE_DIR}"
        "${DATA_BASE_DIR}"
        "${SOFTWARE_BASE_DIR}"
        "${ORACLE_BASE}"
        "${ORACLE_HOME}"
        "${ORACLE_INVENTORY}"
        "${ORACLE_DATA_DIR}"
        "${ORACLE_SOFTWARE_DIR}"
    )
    
    for dir in "${dirs[@]}"; do
        if [[ ! -d "$dir" ]]; then
            mkdir -p "$dir"
            print_info "创建目录: $dir"
        fi
    done
    
    # 创建数据子目录
    local data_subdirs=(
        "oradata"
        "archivelog"
        "redo"
        "standby"
        "backup/dump"
        "backup/rman"
        "flash_recovery_area"
    )
    
    for subdir in "${data_subdirs[@]}"; do
        local full_dir="${ORACLE_DATA_DIR}/${subdir}"
        if [[ ! -d "$full_dir" ]]; then
            mkdir -p "$full_dir"
            print_info "创建数据目录: $full_dir"
        fi
    done
    
    # 设置权限
    chown -R "${ORACLE_USER}:${ORACLE_PRIMARY_GROUP}" "${INSTALL_BASE_DIR}" "${DATA_BASE_DIR}" "${SOFTWARE_BASE_DIR}"
    chmod -R 775 "${INSTALL_BASE_DIR}" "${DATA_BASE_DIR}" "${SOFTWARE_BASE_DIR}"
    
    print_info "目录权限已设置"
    
    mark_step_completed "create_oracle_directories"
}

# 配置Oracle环境变量
configure_oracle_env() {
    if check_step_completed "configure_oracle_env"; then
        return 0
    fi
    
    print_step "配置Oracle环境变量..."
    
    local bash_profile="/home/${ORACLE_USER}/.bash_profile"
    
    # 备份现有配置
    if [[ -f "$bash_profile" ]]; then
        cp "$bash_profile" "${bash_profile}.backup.$(date +%Y%m%d)"
    fi
    
    # 添加Oracle环境变量
    cat >> "$bash_profile" << EOF

# Oracle环境变量
export ORACLE_BASE=${ORACLE_BASE}
export ORACLE_HOME=${ORACLE_HOME}
export ORACLE_SID=${ORACLE_SID}
export ORACLE_UNQNAME=${ORACLE_SID}
export PATH=\$ORACLE_HOME/bin:\$PATH
export LD_LIBRARY_PATH=\$ORACLE_HOME/lib:/lib:/usr/lib
export CLASSPATH=\$ORACLE_HOME/jlib:\$ORACLE_HOME/rdbms/jlib
export NLS_LANG=AMERICAN_AMERICA.${ORACLE_CHARSET}
export TMP=/tmp
export TMPDIR=\$TMP
umask 022
EOF
    
    # 应用环境变量
    chown "${ORACLE_USER}:${ORACLE_PRIMARY_GROUP}" "$bash_profile"
    
    print_info "Oracle环境变量已配置"
    
    mark_step_completed "configure_oracle_env"
}

# 解压Oracle软件
extract_oracle_software() {
    if check_step_completed "extract_oracle_software"; then
        return 0
    fi
    
    print_step "解压Oracle软件..."
    
    # 检查是否已解压
    if [[ -d "${ORACLE_SOFTWARE_DIR}/database" ]]; then
        print_info "Oracle软件已解压,跳过此步骤"
        mark_step_completed "extract_oracle_software"
        return 0
    fi
    
    # 解压安装包
    for zip_file in "${ORACLE_ZIP_FILES[@]}"; do
        print_info "解压文件: $(basename "$zip_file")"
        unzip -q -d "${ORACLE_SOFTWARE_DIR}" "$zip_file" >> "${INSTALL_LOG}" 2>&1
        if [[ $? -ne 0 ]]; then
            print_error "解压失败: $zip_file"
            exit 1
        fi
    done
    
    # 验证解压结果
    if [[ ! -f "${ORACLE_SOFTWARE_DIR}/database/runInstaller" ]]; then
        print_error "解压后找不到runInstaller"
        exit 1
    fi
    
    print_info "Oracle软件解压完成"
    
    mark_step_completed "extract_oracle_software"
}

# 准备响应文件
prepare_response_files() {
    if check_step_completed "prepare_response_files"; then
        return 0
    fi
    
    print_step "准备响应文件..."
    
    local db_install_rsp="${ORACLE_SOFTWARE_DIR}/database/response/db_install.rsp"
    local dbca_rsp="${ORACLE_SOFTWARE_DIR}/database/response/dbca.rsp"
    local netca_rsp="${ORACLE_SOFTWARE_DIR}/database/response/netca.rsp"
    
    # 复制响应文件模板
    if [[ ! -f "${db_install_rsp}.template" ]]; then
        cp "$db_install_rsp" "${db_install_rsp}.template"
    fi
    
    if [[ ! -f "${dbca_rsp}.template" ]]; then
        cp "$dbca_rsp" "${dbca_rsp}.template"
    fi
    
    # 修改db_install.rsp
    sed -i \
        -e "s|^oracle.install.option=$|oracle.install.option=INSTALL_DB_SWONLY|" \
        -e "s|^UNIX_GROUP_NAME=$|UNIX_GROUP_NAME=${ORACLE_PRIMARY_GROUP}|" \
        -e "s|^INVENTORY_LOCATION=$|INVENTORY_LOCATION=${ORACLE_INVENTORY}|" \
        -e "s|^ORACLE_HOME=$|ORACLE_HOME=${ORACLE_HOME}|" \
        -e "s|^ORACLE_BASE=$|ORACLE_BASE=${ORACLE_BASE}|" \
        -e "s|^oracle.install.db.InstallEdition=$|oracle.install.db.InstallEdition=EE|" \
        -e "s|^oracle.install.db.DBA_GROUP=$|oracle.install.db.DBA_GROUP=${ORACLE_DBA_GROUP}|" \
        -e "s|^oracle.install.db.OPER_GROUP=$|oracle.install.db.OPER_GROUP=${ORACLE_OPER_GROUP}|" \
        -e "s|^DECLINE_SECURITY_UPDATES=$|DECLINE_SECURITY_UPDATES=true|" \
        -e "s|^SECURITY_UPDATES_VIA_MYORACLESUPPORT=$|SECURITY_UPDATES_VIA_MYORACLESUPPORT=false|" \
        "$db_install_rsp" 
    local setp_status=$?
    
    if [[ $setp_status -eq 0 ]];then
        print_info "响应文件准备完成:$db_install_rsp"
    else
        print_error "响应文件:$db_install_rsp 配置失败,退出"
        exit 1
    fi 

    # 修改dbca.rsp
    sed -i \
       -e "s|^GDBNAME = \"orcl11g.us.oracle.com\"|GDBNAME = \"${ORACLE_SID}\"|"  \
       -e "s|^SID = \"orcl11g\"|SID = \"${ORACLE_SID}\"|"  \
       -e "s|#SYSPASSWORD = \"password\"|SYSPASSWORD = \"oracle\"|"  \
       -e "s|#SYSTEMPASSWORD = \"password\"|SYSTEMPASSWORD = \"oracle\"|"  \
       -e "s|#EMCONFIGURATION = \"NONE\"|EMCONFIGURATION = \"NONE\"|"  \
       -e "s|#SYSMANPASSWORD = \"password\"|SYSMANPASSWORD = \"oracle\"|"  \
       -e "s|#DBSNMPPASSWORD = \"password\"|DBSNMPPASSWORD = \"oracle\"|"  \
       -e "s|#CHARACTERSET = \"US7ASCII\"|CHARACTERSET = \"ZHS16GBK\"|"  \
       -e "s|#MEMORYPERCENTAGE = \"40\"|MEMORYPERCENTAGE = \"70\"|"  \
       "$dbca_rsp"
    setp_status=$?
    
    if [[ $setp_status -eq 0 ]];then
        print_info "响应文件准备完成:$dbca_rsp"
    else
        print_error "响应文件:$dbca_rsp 配置失败,退出"
        exit 1
    fi
    
    mark_step_completed "prepare_response_files"
}

# 安装Oracle软件
install_oracle_software() {
    if check_step_completed "install_oracle_software"; then
        return 0
    fi
    
    print_step "开始安装Oracle软件..."
    
    local db_install_rsp="${ORACLE_SOFTWARE_DIR}/database/response/db_install.rsp"
    
    # 检查是否已安装
    if [[ -f "${ORACLE_HOME}/bin/oracle" ]]; then
        print_info "Oracle软件已安装,跳过此步骤"
        mark_step_completed "install_oracle_software"
        return 0
    fi
    
    # 以oracle用户身份安装
    print_info "执行安装命令..."
    su - "${ORACLE_USER}" -c "
        cd '${ORACLE_SOFTWARE_DIR}/database'
        ./runInstaller -silent -waitforcompletion -ignoreSysPrereqs \
        -responseFile '${db_install_rsp}' \
        -ignorePrereq -showProgress
    " >> "${INSTALL_LOG}" 2>&1
    
    local install_result=$?
    
    if [[ $install_result -eq 0 ]]; then
        print_info "Oracle软件安装成功"
        
        # 执行root脚本
        if [[ -f "${ORACLE_INVENTORY}/orainstRoot.sh" ]]; then
            print_info "执行orainstRoot.sh"
            "${ORACLE_INVENTORY}/orainstRoot.sh" >> "${INSTALL_LOG}" 2>&1
        fi
        
        if [[ -f "${ORACLE_HOME}/root.sh" ]]; then
            print_info "执行root.sh"
            "${ORACLE_HOME}/root.sh" >> "${INSTALL_LOG}" 2>&1
        fi
    else
        print_error "Oracle软件安装失败,退出码: $install_result"
        print_error "请检查日志文件: ${INSTALL_LOG}"
        exit 1
    fi
    
    mark_step_completed "install_oracle_software"
}

# 配置监听器
configure_listener() {
    if check_step_completed "configure_listener"; then
        return 0
    fi
    
    print_step "配置监听器..."
    
    # 创建listener.ora
    cat > "${ORACLE_HOME}/network/admin/listener.ora" << EOF
LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = ${HOSTNAME})(PORT = 1521))
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
    )
  )

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (GLOBAL_DBNAME = ${ORACLE_SID})
      (ORACLE_HOME = ${ORACLE_HOME})
      (SID_NAME = ${ORACLE_SID})
    )
  )
EOF
    
    # 创建tnsnames.ora
    cat > "${ORACLE_HOME}/network/admin/tnsnames.ora" << EOF
${ORACLE_SID} =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = ${HOSTNAME})(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ${ORACLE_SID})
    )
  )
EOF
    
    # 设置权限
    chown -R "${ORACLE_USER}:${ORACLE_DBA_GROUP}" "${ORACLE_HOME}/network/admin"
    
    # 启动监听器
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        lsnrctl stop >> /dev/null 2>&1
        lsnrctl start
    " >> "${INSTALL_LOG}" 2>&1
    
    print_info "监听器配置完成"
    
    mark_step_completed "configure_listener"
}

# 检查数据库是否已存在
check_database_existence() {
    print_step "检查数据库实例是否存在..."
    
    local db_status="NOT_EXIST"
    
    # 方法1: 检查参数文件
    local param_files=(
        "${ORACLE_HOME}/dbs/spfile${ORACLE_SID}.ora"
        "${ORACLE_HOME}/dbs/init${ORACLE_SID}.ora"
    )
    
    # 方法2: 检查进程
    local pmon_process=$(ps -ef | grep -v grep | grep ora_pmon_${ORACLE_SID} 2>/dev/null)
    
    for param_file in "${param_files[@]}"; do
        if [[ -f "$param_file" ]]; then
            print_warn "找到参数文件: $param_file"
            db_status="PARAM_EXISTS"
            break
        fi
    done
    
    if [[ -n "$pmon_process" ]]; then
        print_warn "找到数据库进程 ora_pmon_${ORACLE_SID}"
        db_status="RUNNING"
    fi
    
    if [[ "$db_status" != "NOT_EXIST" ]]; then
        echo "================================================"
        print_warn "数据库实例 ${ORACLE_SID} 可能已存在!"
        echo "当前状态: $db_status"
        echo ""
        echo "如果要重新安装,请执行以下操作:"
        echo "1. 备份现有数据"
        echo "2. 停止数据库: sqlplus / as sysdba <<< 'shutdown immediate'"
        echo "3. 删除相关文件"
        echo "================================================"
        
        read -p "是否继续创建数据库?(yes/no): " -t 30 confirm_db
        if [[ "${confirm_db}" != "yes" ]]; then
            print_info "用户取消数据库创建"
            return 1
        fi
    fi
    
    return 0
}

# 创建数据库
create_database() {
    if check_step_completed "create_database"; then
        return 0
    fi
    
    print_step "开始创建数据库..."
    
    # 检查数据库是否已存在
    if ! check_database_existence; then
        return 1
    fi
    
    local dbca_rsp="${ORACLE_SOFTWARE_DIR}/database/response/dbca.rsp"
    
    # 修改数据库安装模板
    if [[ -f "$ORACLE_General_Purpose" ]]; then
        sed -i "s#{ORACLE_BASE}/oradata/{DB_UNIQUE_NAME}#$ORACLE_DATA_DIR/oradata#g" "$ORACLE_General_Purpose"
        print_info "$ORACLE_General_Purpose 已经修改完成"
    fi

    # 创建数据库
    print_info "使用dbca创建数据库实例..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        dbca -silent -responseFile '${dbca_rsp}'
    " >> "${INSTALL_LOG}" 2>&1
    
    local dbca_result=$?
    
    if [[ $dbca_result -eq 0 ]]; then
        print_info "数据库创建成功"
        
        # 等待数据库完全启动
        sleep 30
        
        # 验证数据库状态
        if su - "${ORACLE_USER}" -c "
            export ORACLE_HOME=${ORACLE_HOME}
            export ORACLE_SID=${ORACLE_SID}
            export PATH=\${ORACLE_HOME}/bin:\${PATH}
            sqlplus -S / as sysdba << 'SQL'
            SELECT 'DATABASE_STATUS:' || status FROM v\\\$instance;
            exit;
SQL
        " | grep -q "DATABASE_STATUS:OPEN"; then
            print_info "数据库已成功打开"
        else
            print_warn "数据库可能未完全启动"
        fi
    else
        print_error "数据库创建失败,退出码: $dbca_result"
        exit 1
    fi
    
    mark_step_completed "create_database"
}

# 配置数据库参数
configure_database_parameters() {
    if check_step_completed "configure_database_parameters"; then
        return 0
    fi
    
    print_step "配置数据库参数..."
    
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus / as sysdba << 'SQL'
        -- 启用归档模式
        SHUTDOWN IMMEDIATE;
        STARTUP MOUNT;
        ALTER DATABASE ARCHIVELOG;
        ALTER DATABASE OPEN;
        
        -- 设置归档目录
        ALTER SYSTEM SET log_archive_dest_1='location=${ORACLE_DATA_DIR}/archivelog' SCOPE=SPFILE;
        
        -- 调整内存参数
        ALTER SYSTEM SET sga_target=2G SCOPE=SPFILE;
        ALTER SYSTEM SET pga_aggregate_target=1G SCOPE=SPFILE;
        
        -- 调整其他参数
        ALTER SYSTEM SET processes=500 SCOPE=SPFILE;
        ALTER SYSTEM SET open_cursors=300 SCOPE=SPFILE;
        ALTER SYSTEM SET session_cached_cursors=100 SCOPE=SPFILE;
        
        -- 重启使参数生效
        SHUTDOWN IMMEDIATE;
        STARTUP;
        
        -- 创建pfile备份
        CREATE PFILE='${ORACLE_HOME}/dbs/init${ORACLE_SID}.ora' FROM SPFILE;
        
        exit;
SQL
    " >> "${INSTALL_LOG}" 2>&1
    
    print_info "数据库参数配置完成"
    
    mark_step_completed "configure_database_parameters"
}

# ============================================================================
# 验证函数库
# ============================================================================

# 增强验证安装
enhanced_validate_installation() {
    print_step "增强验证Oracle安装..."
    
    # 检查关键文件
    local critical_files=(
        "${ORACLE_HOME}/bin/oracle"
        "${ORACLE_HOME}/bin/sqlplus"
        "${ORACLE_HOME}/network/admin/listener.ora"
        "${ORACLE_HOME}/network/admin/tnsnames.ora"
        "${ORACLE_HOME}/dbs/spfile${ORACLE_SID}.ora"
    )
    
    print_info "检查关键文件..."
    for file in "${critical_files[@]}"; do
        if [[ -f "$file" ]]; then
            print_info "✓ $file 存在"
        else
            print_warn "✗ $file 不存在"
        fi
    done
    
    # 检查Oracle用户环境
    print_info "检查Oracle用户环境..."
    su - "${ORACLE_USER}" -c "
        echo 'ORACLE_HOME: \$ORACLE_HOME'
        echo 'ORACLE_SID: \$ORACLE_SID'
        echo 'PATH包含ORACLE_HOME: \$(echo \$PATH | grep \$ORACLE_HOME)'
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 检查监听器状态
    print_info "检查监听器状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        lsnrctl status 2>&1 | grep -A 5 -B 2 \"STATUS\"
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 检查数据库状态
    print_info "检查数据库状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << EOF
        set pagesize 0 linesize 100 feedback off
        select 'DB_NAME: '||name from v\\\$database;
        select 'DB_STATUS: '||status from v\\\$instance;
        select 'OPEN_MODE: '||open_mode from v\\\$database;
        select 'CONTROLFILE: '||name from v\\\$controlfile;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 测试监听器连接
    print_info "测试监听器连接..."
    tnsping_result=$(su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        tnsping ${ORACLE_SID} 2>&1
    " | grep "OK")
    
    if [[ -n "$tnsping_result" ]]; then
        print_info "✓ 监听器连接正常"
    else
        print_warn "✗ 监听器连接失败"
    fi
    
    print_info "增强验证完成"
}

# 验证安装
validate_installation() {
    print_step "验证Oracle安装..."
    
    # 1. 检查监听器
    print_info "检查监听器状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        lsnrctl status 2>&1 | grep -A 5 -B 2 \"STATUS\"
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 2. 检查数据库状态
    print_info "检查数据库状态..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << EOF
        set pagesize 0 linesize 100 feedback off
        select 'DB_NAME: '||name from v\\\$database;
        select 'DB_STATUS: '||status from v\\\$instance;
        select 'OPEN_MODE: '||open_mode from v\\\$database;
        select 'CONTROLFILE: '||name from v\\\$controlfile;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 3. 检查表空间
    print_info "检查表空间..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << 'EOF'
        set pagesize 0 linesize 100 feedback off
        col \"Tablespace\" format a20
        col \"Used %\" format a10
        select tablespace_name \"Tablespace\",
               round(used_percent,2)||'%' \"Used %\"
        from dba_tablespace_usage_metrics
        order by tablespace_name;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    # 4. 检查数据文件
    print_info "检查数据文件..."
    su - "${ORACLE_USER}" -c "
        export ORACLE_HOME=${ORACLE_HOME}
        export ORACLE_SID=${ORACLE_SID}
        export PATH=\${ORACLE_HOME}/bin:\${PATH}
        sqlplus -S / as sysdba << 'EOF'
        set pagesize 0 linesize 150 feedback off
        col \"Datafile\" format a60
        col \"Size(MB)\" format 999999
        select file_name \"Datafile\", 
               round(bytes/1024/1024) \"Size(MB)\"
        from dba_data_files
        order by tablespace_name, file_id;
        exit;
EOF
    " 2>&1 | tee -a "${INSTALL_LOG}"
    
    print_info "Oracle安装验证完成"
}

# ============================================================================
# 显示函数库
# ============================================================================

# 显示安装摘要
show_summary() {
    cat << EOF

===============================================================
Oracle 11.2.0.4 安装完成!
===============================================================
安装模式: ${INSTALL_MODE}
安装信息:
  主机名: ${HOSTNAME}
  Oracle SID: ${ORACLE_SID}
  字符集: ${ORACLE_CHARSET}

连接信息:
  监听端口: 1521
  系统用户: sys/${SYS_PASSWORD}
  系统用户: system/${SYSTEM_PASSWORD}

目录结构:
  ORACLE_BASE: ${ORACLE_BASE}
  ORACLE_HOME: ${ORACLE_HOME}
  数据文件: ${ORACLE_DATA_DIR}/oradata
  归档日志: ${ORACLE_DATA_DIR}/archivelog
  备份目录: ${ORACLE_DATA_DIR}/backup

验证步骤:
  1. 检查监听器: lsnrctl status
  2. 连接数据库: sqlplus system/${SYSTEM_PASSWORD}@${ORACLE_SID}
  3. 查看状态: SELECT name, open_mode FROM v\\\$database;

日志文件:
  安装日志: ${INSTALL_LOG}
  错误日志: ${ERROR_LOG}
===============================================================
EOF
}

# ============================================================================
# 安装流程函数
# ============================================================================

# 完整安装流程
install_full() {
    print_step "开始完整安装Oracle..."
    
    local install_steps=(
        "stop_oracle_processes"
        "install_dependencies"
        "create_oracle_user"
        "configure_kernel_parameters"
        "configure_user_limits"
        "create_oracle_directories"
        "configure_oracle_env"
        "extract_oracle_software"
        "prepare_response_files"
        "install_oracle_software"
        "configure_listener"
        "create_database"
        "configure_database_parameters"
    )
    
    # 执行安装步骤
    for step in "${install_steps[@]}"; do
        echo "$(date): 执行步骤: ${step}" | tee -a "${INSTALL_LOG}"
        if ! ${step}; then
            echo "$(date): 错误: 步骤 ${step} 执行失败" | tee -a "${INSTALL_LOG}"
            exit 1
        fi
    done
    
    # 验证安装
    enhanced_validate_installation
    
    # 显示摘要
    show_summary
    
    print_info "Oracle完整安装完成"
}

# 只安装软件
install_software_only() {
    print_step "开始只安装Oracle软件..."
    
    local install_steps=(
        "stop_oracle_processes"
        "install_dependencies"
        "create_oracle_user"
        "configure_kernel_parameters"
        "configure_user_limits"
        "create_oracle_directories"
        "configure_oracle_env"
        "extract_oracle_software"
        "prepare_response_files"
        "install_oracle_software"
        "configure_listener"
    )
    
    # 执行安装步骤
    for step in "${install_steps[@]}"; do
        echo "$(date): 执行步骤: ${step}" | tee -a "${INSTALL_LOG}"
        if ! ${step}; then
            echo "$(date): 错误: 步骤 ${step} 执行失败" | tee -a "${INSTALL_LOG}"
            exit 1
        fi
    done
    
    print_info "Oracle软件安装完成"
    echo ""
    echo "软件安装完成,可以运行以下命令创建数据库:"
    echo "  1. 切换到oracle用户: su - oracle"
    echo "  2. 创建数据库: dbca -silent -createDatabase -templateName General_Purpose.dbc ..."
    echo "  或运行完整安装: $0 --database-only"
}

# 只创建数据库
install_database_only() {
    print_step "开始只创建数据库..."
    
    # 验证软件是否已安装
    if [[ ! -f "${ORACLE_HOME}/bin/oracle" ]]; then
        print_error "Oracle软件未安装,请先安装软件"
        echo "运行: $0 --software-only"
        exit 1
    fi
    
    local install_steps=(
        "configure_listener"
        "create_database"
        "configure_database_parameters"
    )
    
    # 执行安装步骤
    for step in "${install_steps[@]}"; do
        echo "$(date): 执行步骤: ${step}" | tee -a "${INSTALL_LOG}"
        if ! ${step}; then
            echo "$(date): 错误: 步骤 ${step} 执行失败" | tee -a "${INSTALL_LOG}"
            exit 1
        fi
    done
    
    # 验证安装
    validate_installation
    
    print_info "数据库创建完成"
}

# ============================================================================
# 主控制函数
# ============================================================================

main() {
    # 解析命令行参数
    parse_arguments "$@"
    
    # 检查root权限
    check_root
    
    # 初始化环境
    init_environment
    
    # 根据模式执行不同操作
    case "$INSTALL_MODE" in
        "check")
            check_environment
            ;;
        "software-only")
            # 确认继续
            read -p "是否继续安装Oracle软件? (yes/no): " confirm
            if [[ "${confirm}" != "yes" ]]; then
                print_info "用户取消安装"
                exit 0
            fi
            install_software_only
            ;;
        "database-only")
            # 确认继续
            read -p "是否继续创建数据库? (yes/no): " confirm
            if [[ "${confirm}" != "yes" ]]; then
                print_info "用户取消安装"
                exit 0
            fi
            install_database_only
            ;;
        "clean")
            clean_installation
            ;;
        "full")
            # 检查Oracle软件
            if ! check_oracle_software; then
                exit 1
            fi
            
            # 确认继续
            read -p "是否继续完整安装? (yes/no): " confirm
            if [[ "${confirm}" != "yes" ]]; then
                print_info "用户取消安装"
                exit 0
            fi
            install_full
            ;;
        *)
            print_error "未知的安装模式: $INSTALL_MODE"
            show_usage
            ;;
    esac
    
    echo "$(date): 操作完成" | tee -a "${INSTALL_LOG}"
}

# ============================================================================
# 脚本入口
# ============================================================================

# 捕获中断信号
trap 'print_info "安装被用户中断"; exit 1' INT TERM

# 执行主函数
main "$@"

exit 0
View Code

9. 脚本执行过程

[root@zb-yunweitest-mysql-204-200 oracle]# sh ora_install.sh 
================================================================
开始Oracle 11.2.0.4静默安装
================================================================
安装模式:           full
主机名:             zb-yunweitest-mysql-204-200
IP地址:             172.21.204.200
Oracle SID:         caiwu
Oracle基目录:       /data/u01/app/oracle
数据目录:           /data/u02/caiwu
安装组件的状态目录:/tmp/oracle_install_state_20251208_201512
安装日志文件:      /var/log/oracle_install_20251208_201512/install.log
安装错误日志文件:  /var/log/oracle_install_20251208_201512/error.log
================================================================
[INFO] 初始化完成
Mon Dec  8 20:15:12 CST 2025: 初始化完成
[STEP] 检查Oracle安装文件...
[INFO] 找到安装文件: /data/dba/oracle/p13390677_112040_Linux-x86-64_1of7.zip
  文件大小: 1.3G
[INFO] 找到安装文件: /data/dba/oracle/p13390677_112040_Linux-x86-64_2of7.zip
  文件大小: 1.1G
[INFO] Oracle安装文件检查完成
是否继续完整安装? (yes/no): yes
[STEP] 开始完整安装Oracle...
Mon Dec  8 20:15:13 CST 2025: 执行步骤: stop_oracle_processes
[STEP] 检查Oracle用户进程...
[STEP] 强制清理所有Oracle相关进程...
[INFO] 安全地清理Oracle进程...
[INFO] 检查是否有残留的Oracle进程...
[INFO] 进程清理完成
[INFO] 未找到Oracle用户进程
[STEP] 清理Oracle共享内存和信号量...
检查Oracle共享内存段...
[INFO] 未找到Oracle共享内存段
检查Oracle信号量...
[INFO] 未找到Oracle信号量
检查Oracle消息队列...
[INFO] 未找到Oracle消息队列
检查/dev/shm中的Oracle文件...
[INFO] IPC资源清理完成
Mon Dec  8 20:15:17 CST 2025: 执行步骤: install_dependencies
[STEP] 开始安装依赖包...
Mon Dec  8 20:15:17 CST 2025: 包 binutils 已安装
Mon Dec  8 20:15:17 CST 2025: 包 compat-libcap1 已安装
Mon Dec  8 20:15:17 CST 2025: 包 compat-libstdc++-33 已安装
Mon Dec  8 20:15:17 CST 2025: 包 gcc 已安装
Mon Dec  8 20:15:17 CST 2025: 包 gcc-c++ 已安装
Mon Dec  8 20:15:17 CST 2025: 包 glibc 已安装
Mon Dec  8 20:15:17 CST 2025: 包 glibc-devel 已安装
Mon Dec  8 20:15:17 CST 2025: 包 ksh 已安装
Mon Dec  8 20:15:17 CST 2025: 包 libgcc 已安装
Mon Dec  8 20:15:17 CST 2025: 包 libstdc++ 已安装
Mon Dec  8 20:15:17 CST 2025: 包 libstdc++-devel 已安装
Mon Dec  8 20:15:17 CST 2025: 包 libaio 已安装
Mon Dec  8 20:15:17 CST 2025: 包 libaio-devel 已安装
Mon Dec  8 20:15:17 CST 2025: 包 libXext 已安装
Mon Dec  8 20:15:18 CST 2025: 包 libXtst 已安装
Mon Dec  8 20:15:18 CST 2025: 包 libX11 已安装
Mon Dec  8 20:15:18 CST 2025: 包 libXau 已安装
Mon Dec  8 20:15:18 CST 2025: 包 libxcb 已安装
Mon Dec  8 20:15:18 CST 2025: 包 libXi 已安装
Mon Dec  8 20:15:18 CST 2025: 包 make 已安装
Mon Dec  8 20:15:18 CST 2025: 包 sysstat 已安装
Mon Dec  8 20:15:18 CST 2025: 包 unzip 已安装
Mon Dec  8 20:15:18 CST 2025: 包 unixODBC 已安装
Mon Dec  8 20:15:18 CST 2025: 包 unixODBC-devel 已安装
Mon Dec  8 20:15:18 CST 2025: 步骤 install_dependencies 完成
[INFO] 依赖包安装完成
Mon Dec  8 20:15:18 CST 2025: 执行步骤: create_oracle_user
[STEP] 创建Oracle用户和组...
[INFO] 创建组: oinstall
[INFO] 创建组: dba
[INFO] 创建组: oper
Creating mailbox file: File exists
[INFO] 创建用户: oracle
Mon Dec  8 20:15:18 CST 2025: 步骤 create_oracle_user 完成
Mon Dec  8 20:15:18 CST 2025: 执行步骤: configure_kernel_parameters
[STEP] 配置内核参数...
[INFO] 内核参数已配置,跳过
[INFO] 内核参数已应用
Mon Dec  8 20:15:18 CST 2025: 步骤 configure_kernel_parameters 完成
Mon Dec  8 20:15:18 CST 2025: 执行步骤: configure_user_limits
[STEP] 配置用户资源限制...
[INFO] 用户资源限制已存在,跳过
Mon Dec  8 20:15:18 CST 2025: 步骤 configure_user_limits 完成
Mon Dec  8 20:15:18 CST 2025: 执行步骤: create_oracle_directories
[STEP] 创建Oracle目录结构...
[INFO] 创建目录: /data/u01
[INFO] 创建目录: /data/u02
[INFO] 创建目录: /data/u01/app/oracle
[INFO] 创建目录: /data/u01/app/oracle/product/11.2.0.4/db_1
[INFO] 创建目录: /data/u01/app/oraInventory
[INFO] 创建目录: /data/u02/caiwu
[INFO] 创建目录: /data/dba/oracle/software
[INFO] 创建数据目录: /data/u02/caiwu/oradata
[INFO] 创建数据目录: /data/u02/caiwu/archivelog
[INFO] 创建数据目录: /data/u02/caiwu/redo
[INFO] 创建数据目录: /data/u02/caiwu/standby
[INFO] 创建数据目录: /data/u02/caiwu/backup/dump
[INFO] 创建数据目录: /data/u02/caiwu/backup/rman
[INFO] 创建数据目录: /data/u02/caiwu/flash_recovery_area
[INFO] 目录权限已设置
Mon Dec  8 20:15:18 CST 2025: 步骤 create_oracle_directories 完成
Mon Dec  8 20:15:18 CST 2025: 执行步骤: configure_oracle_env
[STEP] 配置Oracle环境变量...
[INFO] Oracle环境变量已配置
Mon Dec  8 20:15:18 CST 2025: 步骤 configure_oracle_env 完成
Mon Dec  8 20:15:18 CST 2025: 执行步骤: extract_oracle_software
[STEP] 解压Oracle软件...
[INFO] 解压文件: p13390677_112040_Linux-x86-64_1of7.zip
[INFO] 解压文件: p13390677_112040_Linux-x86-64_2of7.zip
[INFO] Oracle软件解压完成
Mon Dec  8 20:15:39 CST 2025: 步骤 extract_oracle_software 完成
Mon Dec  8 20:15:39 CST 2025: 执行步骤: prepare_response_files
[STEP] 准备响应文件...
[INFO] 响应文件准备完成:/data/dba/oracle/software/database/response/db_install.rsp
[INFO] 响应文件准备完成:/data/dba/oracle/software/database/response/dbca.rsp
Mon Dec  8 20:15:39 CST 2025: 步骤 prepare_response_files 完成
Mon Dec  8 20:15:39 CST 2025: 执行步骤: install_oracle_software
[STEP] 开始安装Oracle软件...
[INFO] 执行安装命令...
[INFO] Oracle软件安装成功
[INFO] 执行orainstRoot.sh
[INFO] 执行root.sh
Mon Dec  8 20:17:43 CST 2025: 步骤 install_oracle_software 完成
Mon Dec  8 20:17:43 CST 2025: 执行步骤: configure_listener
[STEP] 配置监听器...
[INFO] 监听器配置完成
Mon Dec  8 20:17:43 CST 2025: 步骤 configure_listener 完成
Mon Dec  8 20:17:43 CST 2025: 执行步骤: create_database
[STEP] 开始创建数据库...
[STEP] 检查数据库实例是否存在...
[INFO] /data/u01/app/oracle/product/11.2.0.4/db_1/assistants/dbca/templates/General_Purpose.dbc 已经修改完成
[INFO] 使用dbca创建数据库实例...
[INFO] 数据库创建成功
[WARN] 数据库可能未完全启动
Mon Dec  8 20:20:16 CST 2025: 步骤 create_database 完成
Mon Dec  8 20:20:16 CST 2025: 执行步骤: configure_database_parameters
[STEP] 配置数据库参数...
[INFO] 数据库参数配置完成
Mon Dec  8 20:20:44 CST 2025: 步骤 configure_database_parameters 完成
[STEP] 增强验证Oracle安装...
[INFO] 检查关键文件...
[INFO] ✓ /data/u01/app/oracle/product/11.2.0.4/db_1/bin/oracle 存在
[INFO] ✓ /data/u01/app/oracle/product/11.2.0.4/db_1/bin/sqlplus 存在
[INFO] ✓ /data/u01/app/oracle/product/11.2.0.4/db_1/network/admin/listener.ora 存在
[INFO] ✓ /data/u01/app/oracle/product/11.2.0.4/db_1/network/admin/tnsnames.ora 存在
[INFO] ✓ /data/u01/app/oracle/product/11.2.0.4/db_1/dbs/spfilecaiwu.ora 存在
[INFO] 检查Oracle用户环境...
ORACLE_HOME: $ORACLE_HOME
ORACLE_SID: $ORACLE_SID
PATH包含ORACLE_HOME: $(echo $PATH | grep $ORACLE_HOME)
[INFO] 检查监听器状态...

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=zb-yunweitest-mysql-204-200)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 11.2.0.4.0 - Production
Start Date                08-DEC-2025 20:17:43
Uptime                    0 days 0 hr. 3 min. 1 sec
[INFO] 检查数据库状态...
DB_NAME: CAIWU
DB_STATUS: OPEN
OPEN_MODE: READ WRITE
CONTROLFILE: /data/u02/caiwu/oradata/control01.ctl
CONTROLFILE: /data/u01/app/oracle/fast_recovery_area/caiwu/control02.ctl
[INFO] 测试监听器连接...
[INFO] ✓ 监听器连接正常
[INFO] 增强验证完成

===============================================================
Oracle 11.2.0.4 安装完成!
===============================================================
安装模式: full
安装信息:
  主机名: zb-yunweitest-mysql-204-200
  Oracle SID: caiwu
  字符集: ZHS16GBK

连接信息:
  监听端口: 1521
  系统用户: sys/oracle
  系统用户: system/oracle

目录结构:
  ORACLE_BASE: /data/u01/app/oracle
  ORACLE_HOME: /data/u01/app/oracle/product/11.2.0.4/db_1
  数据文件: /data/u02/caiwu/oradata
  归档日志: /data/u02/caiwu/archivelog
  备份目录: /data/u02/caiwu/backup

验证步骤:
  1. 检查监听器: lsnrctl status
  2. 连接数据库: sqlplus system/oracle@caiwu
  3. 查看状态: SELECT name, open_mode FROM v\$database;

日志文件:
  安装日志: /var/log/oracle_install_20251208_201512/install.log
  错误日志: /var/log/oracle_install_20251208_201512/error.log
===============================================================
[INFO] Oracle完整安装完成
Mon Dec  8 20:20:44 CST 2025: 操作完成
[root@zb-yunweitest-mysql-204-200 oracle]# 
View Code

 

 posted on 2025-12-08 15:56  xibuhaohao  阅读(58)  评论(0)    收藏  举报