写的一个小玩具
使用方法:
默认的环境变量启动该空壳实例
bak_dir下是所有备份+归档,有多少归档恢复到什么位置,自行保证一致性
restore_dir下展开的数据文件的地方
bak_ctl这个需要自己指定控制文件的备份片
#!/bin/sh
#user define var
restore_dir='/oradata'
bak_dir="'/home/oracle/rmanbak/'"
bak_ctl="'/home/oracle/rmanbak/control.bak'"
database="orcl"
parallelism=4
#prepare
data_dir="${restore_dir}/${database}"
newname_path="'${restore_dir}/${database}/%b'"
logpath="/tmp/restore_${database}.log"
start_nomout(){
# call startup with nomount
sqlplus / as sysdba > ${logpath} << ABC
startup nomount force;
exit;
ABC
}
restore_ctl(){
# call restore controle file and mount database
rman target / log=${logpath} append << QWE
run {
allocate channel ch1 device type disk;
restore controlfile from ${bak_ctl};
RELEASE CHANNEL ch1;
alter database mount;
sql 'alter database flashback off';
}
QWE
}
catalog_bak(){
# call catalog
rman target / log=${logpath} append << ZXC
run {
catalog start with ${bak_dir} noprompt;
crosscheck backupset;
delete noprompt expired backupset;
}
ZXC
}
restore_db(){
# call restore db
rman target / log=${logpath} append << WSX
run {
CONFIGURE DEVICE TYPE DISK PARALLELISM ${parallelism};
set newname for database to ${newname_path};
catalog start with ${bak_dir} noprompt;
restore database;
switch datafile all;
}
WSX
}
recover_db(){
#recover db
rman target / log=${logpath} append << QWE
run {
restore archivelog all;
recover database;
}
QWE
}
open_database(){
#open database resetlogs
sqlplus -s / as sysdba > /tmp/rename_redolog_${database}.sql << EOF
set lines 500;
set pages 500;
set feedback off;
set pagesize 0;
set termout off;
SELECT 'ALTER DATABASE RENAME FILE '''
|| old_redo.redo_files
|| ''' to '''
|| new_redo.new_redo_files
|| ''';' AS command
FROM
(SELECT group_number,
redo_files
FROM
(SELECT group# AS group_number,
listagg(member, ''',''') within GROUP (
ORDER BY group#) AS redo_files
FROM v\$logfile
GROUP BY group#
)
) old_redo,
(SELECT group# AS group_number,
listagg('${data_dir}/'
|| new_redologs, ''',''') within GROUP (
ORDER BY group#) AS new_redo_files
FROM
(SELECT redologs.*,
'redo0'
|| rownum
|| '.log' AS new_redologs
FROM v\$logfile redologs
)
GROUP BY group#
) new_redo
WHERE old_redo.group_number = new_redo.group_number;
EOF
sqlplus / as sysdba >> ${logpath} << EDC
@/tmp/rename_redolog_${database}.sql;
!sleep 3
alter database open resetlogs;
create spfile from pfile;
EDC
}
add_tempfile(){
sqlplus -s / as sysdba > /tmp/add_tempfile_${database}.sql << POI
set lines 500;
set pages 500;
set feedback off;
set pagesize 0;
set termout off;
SELECT distinct 'alter tablespace '||temporary_tablespace||' add tempfile ''${datadir}/'||temporary_tablespace||'.dbf'' size 1g autoextend on;'
from dba_users;
POI
sqlplus / as sysdba >> ${logpath} << LKJ
@/tmp/add_tempfile_${database}.sql;
LKJ
}
main(){
echo "log path: " ${logpath}
echo "data_dir" ${data_dir}
echo "newname_path" ${newname_path}
echo "bak_ctl" ${bak_ctl}
echo "bak_dir "${bak_dir}
mkdir ${data_dir}
####nomount judge
if [ (ps -ef|grep pmon|grep -v grep|grep ${database}|wc -l) < 1 ]; then
start_nomout
fi
sleep 3
####ctl judge
ctl_path=`sqlplus -silent "/ as sysdba" << END
set pagesize 0 feedback off verify off heading off echo off
select name from v\\\$controlfile;
exit;
END`
if [ ! -e "${ctl_path}" | awk 'BEGIN {RS="\\N"} {print $1}' ]; then
restore_ctl
fi
sleep 3
####restore judge
if [ ! find "${datadir}" -maxdepth 0 -type d -empty -exec false {} \; ]; then
restore_db
fi
sleep 3
####recover judge
scn_smooth=`sqlplus -silent "/ as sysdba" << END
set pagesize 0 feedback off verify off heading off echo off
select distinct checkpoint_change# from v\\\$datafile_header;
exit;
END`
if [[ ! ${scn_smooth} =~ \s.+ ]]; then
recover_db
fi
sleep 3
####open judge
database_mode=`sqlplus -silent "/ as sysdba" << END
set pagesize 0 feedback off verify off heading off echo off
select open_mode from v\\\$database ;
exit;
END`
if [[ ! ${database_mode} == *'READ WRITE'* ]]; then
open_database
fi
sleep 3
####add temp judge
if [ -e ${data_dir}/temp.dbf ]; then
add_tempfile
fi
}
main