生產環境常需管理多個 Oracle 實例 (SID),手動操作易出錯且難審計。本文提供一支功能完整的 **Shell 管理腳本**,支援 start|stop|restart 參數化操作、多 SID 逗號分隔批次處理、鎖機制防併發、日誌記錄、systemd 服務整合,並解析關鍵邏輯與部署細節。
./oracled.sh start ORCL,ORCL2,ORCL3/etc/oratab 驗證 SID 合法性#!/bin/bash
# oracled.sh - Oracle 實例啟停管理腳本
# 用法: ./oracled.sh [start|stop|restart] SID1,SID2,...
# 環境: 需預先配置 oracle 用戶 .bash_profile (ORACLE_HOME, PATH 等)
set -euo pipefail
SCRIPT_NAME=$(basename "$0")
LOCK_DIR="/var/lock/oracle"
LOG_DIR="/var/log/oracle"
ORATAB="/etc/oratab"
mkdir -p "$LOCK_DIR" "$LOG_DIR"
usage() {
cat <> "$LOG_FILE"; }
exec_sqlplus() {
local sid=$1
local sql=$2
local log_prefix=$3
export ORACLE_SID="$sid"
log_file "$log_prefix: 執行 SQL: $sql"
sqlplus -s / as sysdba <&1 | tee -a "$LOG_FILE"
WHENEVER SQLERROR EXIT FAILURE
$sql
EXIT
EOF
return ${PIPESTATUS[0]}
}
start_instance() {
local sid=$1
log_file "=== 啟動 $sid ==="
# 1. 啟動監聽器 (僅首個 SID 執行,避免重複)
if [[ "$sid" == "$FIRST_SID" ]]; then
log_file "啟動監聽器..."
lsnrctl start 2>&1 | tee -a "$LOG_FILE"
fi
# 2. 啟動資料庫
exec_sqlplus "$sid" "STARTUP;" "啟動 $sid" || return 1
log_file "=== $sid 啟動成功 ==="
}
stop_instance() {
local sid=$1
log_file "=== 關閉 $sid ==="
exec_sqlplus "$sid" "SHUTDOWN IMMEDIATE;" "關閉 $sid" || return 1
# 最後一個 SID 關閉監聽器
if [[ "$sid" == "$LAST_SID" ]]; then
log_file "關閉監聽器..."
lsnrctl stop 2>&1 | tee -a "$LOG_FILE"
fi
log_file "=== $sid 關閉成功 ==="
}
main() {
[[ $# -lt 1 ]] && usage
local action=$1; shift
[[ "$action" == "--help" || "$action" == "-h" ]] && usage
local sids_input=${1:-}
local sids=()
if [[ -z "$sids_input" ]]; then
# 從 oratab 讀取自動啟動的 SID (最後欄位為 Y)
mapfile -t sids < <(awk -F: '$3=="Y" && $1!~/^#/ {print $1}' "$ORATAB")
[[ ${#sids[@]} -eq 0 ]] && { log "錯誤: $ORATAB 中無自動啟動 SID"; exit 1; }
else
IFS=',' read -ra sids <<< "$sids_input"
fi
FIRST_SID=${sids[0]}
LAST_SID=${sids[-1]}
LOG_FILE="$LOG_DIR/oracled_${action}_$(date +%F_%H%M%S).log"
log "開始 $action 操作,目標 SID: ${sids[*]}"
log_file "開始 $action,SID: ${sids[*]}"
for sid in "${sids[@]}"; do
# 驗證 SID 存在於 oratab
if ! grep -q "^${sid}:" "$ORATAB"; then
log "警告: $sid 不在 $ORATAB 中,跳過"
continue
fi
# 鎖檢查
local lock_file="$LOCK_DIR/${sid}.lock"
if [[ -f "$lock_file" ]] && kill -0 "$(cat "$lock_file" 2>/dev/null)" 2>/dev/null; then
log "錯誤: $sid 正在被其他進程操作 (PID: $(cat "$lock_file"))"
exit 1
fi
echo $$ > "$lock_file"
case "$action" in
start)
start_instance "$sid" || { log "啟動 $sid 失敗"; rm -f "$lock_file"; exit 1; }
;;
stop)
stop_instance "$sid" || { log "關閉 $sid 失敗"; rm -f "$lock_file"; exit 1; }
;;
restart)
stop_instance "$sid" || { log "關閉 $sid 失敗"; rm -f "$lock_file"; exit 1; }
sleep 3
start_instance "$sid" || { log "啟動 $sid 失敗"; rm -f "$lock_file"; exit 1; }
;;
*)
usage
;;
esac
rm -f "$lock_file"
done
log "所有操作完成,日誌: $LOG_FILE"
}
main "$@"
# 1. 複製腳本
cp oracled.sh /usr/local/bin/oracled
chmod 755 /usr/local/bin/oracled
chown oracle:oinstall /usr/local/bin/oracled
# 2. 建立日誌/鎖目錄權限
mkdir -p /var/log/oracle /var/lock/oracle
chown oracle:oinstall /var/log/oracle /var/lock/oracle
# 3. 配置 /etc/oratab (由 root 或 oracle 維護)
# 格式: SID:ORACLE_HOME:Y|N
# 範例:
ORCL:/u01/app/oracle/product/19.0.0/dbhome_1:Y
ORCL2:/u01/app/oracle/product/19.0.0/dbhome_1:N
# 4. 配置 oracle 用戶 sudo 權限 (可選,systemd 需要)
# visudo 添加:
oracle ALL=(root) NOPASSWD: /bin/systemctl start oracle-*, /bin/systemctl stop oracle-*
# /etc/systemd/system/oracle-db@.service
[Unit]
Description=Oracle Database %i
After=network.target oracle-listener.service
Requires=oracle-listener.service
[Service]
Type=oneshot
User=oracle
Group=oinstall
Environment=ORACLE_SID=%i
ExecStart=/usr/local/bin/oracled start %i
ExecStop=/usr/local/bin/oracled stop %i
RemainAfterExit=yes
TimeoutSec=600
[Install]
WantedBy=multi-user.target
# 啟用實例服務
systemctl daemon-reload
systemctl enable oracle-db@ORCL
systemctl start oracle-db@ORCL
systemctl status oracle-db@ORCL
監聽器服務獨立管理:
# /etc/systemd/system/oracle-listener.service
[Unit]
Description=Oracle Listener
After=network.target
[Service]
Type=forking
User=oracle
Group=oinstall
Environment=ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1
ExecStart=/u01/app/oracle/product/19.0.0/dbhome_1/bin/lsnrctl start
ExecStop=/u01/app/oracle/product/19.0.0/dbhome_1/bin/lsnrctl stop
[Install]
WantedBy=multi-user.target
# 手動操作
sudo -u oracle /usr/local/bin/oracled start ORCL
sudo -u oracle /usr/local/bin/oracled stop ORCL,ORCL2
sudo -u oracle /usr/local/bin/oracled restart ORCL
# systemd 操作
systemctl start oracle-db@ORCL
systemctl stop oracle-db@ORCL
systemctl restart oracle-db@ORCL
# 查看日誌
tail -f /var/log/oracle/oracled_start_2024-01-15_143000.log
journalctl -u oracle-db@ORCL -f
| 設計點 | 實現方式 | 效益 |
|---|---|---|
| 多 SID 批次 | 逗號分隔 + 迴圈 + FIRST/LAST 判斷監聽器 | 單命令管理叢集/多實例 | 防併發鎖 | /var/lock/oracle/SID.lock + PID 檢查 | 避免同一實例並行啟停導致損壞 |
| 環境隔離 | 迴圈內 export ORACLE_SID | 各實例獨立環境,互不干擾 |
| 錯誤快速失敗 | set -euo pipefail + sqlplus WHENEVER SQLERROR EXIT FAILURE | 任何步驟失敗立即中止,防止部分成功 |
| 審計日誌 | 雙重輸出 (螢幕 + 檔案) + 時間戳 | 滿足合規、事後追溯 |
status 子命令:檢查實例狀態、監聽器狀態、表空間使用率RMAN 備份腳本:./oracled.sh backup ORCLPFILE 指定啟動:start ORCL /custom/init.ora部署此腳本並納入變更管理流程,可將 Oracle 實例啟停操作標準化、自動化、可審計,顯著降低人為誤操作風險,提升運維效率。