linux下的mysql自動備份shell

jopen 9年前發布 | 7K 次閱讀 Shell MySQL

    #!/bin/bash

# mysql 的備份腳本  
# 備份原理:  
# 1  
#   使用列舉出所有的庫;  
# 2  
#   使用每個庫,列舉出每張表,除了指定忽略的庫;  
# 3  
#   使用mysqldump 導出每一張表到文件:主機名/年月日/庫/表.mysqldump.sql  
# 4  
#   驗證每張表的sql文件是否包含完成標志;  
# 5  
#   壓縮每個sql文件并刪除本sql文件  
# 6  
#   強制刪除超過x天的備份文件夾全部文件  
# 7  
#   發送處理日志到指定email  
# 8  
#   請配合同步工具多處服務器備份  

# mysql備份配置信息  

mysqlBackupUser="backuper"  
# 密碼不要包含"號  
mysqlBackupPwd="**#&&&#ddddddd("  
# 日志文件路徑/var/log/文件名.log,只記錄每次運行的日志  
# 不備份的數據庫名稱,每個名稱使用()號包住,如不備份 abc.d 和 abc.e二個數據庫,就拼寫成"(abc.d)(abc.e)",名字不區分大小寫  
notBackupDatabases="(mysql)(information_schema)(performance_schema)"  
#備份的目錄,后面需要加/  
backupRoot="/var/backup/hostname-mysql-data/"  
# 刪除存在大于以下天數的備份目錄  
deleteRootOutDays=30  
#必須是完整的email地址,因為正面的命令使用到  
smtpUser="qidizi@qq.com"  
#smtp://協議是必須的  
smtpHost="smtp://smtp.qq.com:25"  
#密碼不能包含又引號防止shell出錯  
smtpPwd="pwd"  
smtpTo="qq@qq.com"  
smtpSubject="主機上的mysql自動備份腳本執行信息"  
# 配置結束行  

shName=$(basename $0)  
shLogPath="/var/log/${shName}.log"  

ver=$(realpath --version 2>&1)  

if [ "$?" -ne "0" ];then  
    echo "測試realpath --version的版本時出錯,中止,出錯信息:${ver}"  
    exit 10  
fi  

echo -e "$(date "+%Y-%m-%d %R:%S") By $(realpath ${0})\n" > $shLogPath  

function myExit(){  
    exitCode=$1  
    ver=$(mailx -V 2>&1)  
    appendLog "退出時間:$(date +%Y-%m-%d/%R:%S)"  
    appendLog "服務器信息:\n$(ifconfig 2>&1)"  

    if [ "$?" -ne "0" ];then  
        appendLog "測試用來發送email的命令mailx時出錯,請安裝,如centos使用yum install mailx,忽略發送email通知的步驟,出錯信息:${ver}"  
    else  
        #發送email  
        mailInfo=$(mailx -v -s "${smtpSubject}" -S from="${smtpUser}"  -S smtp-auth="login" -S smtp="${smtpHost}" -S smtp-auth-user="${smtpUser}" -S smtp-auth-password="${smtpPwd}" -S ssl-verify=ignore  "${smtpTo}" < $shLogPath 2>&1)  
        # 無法附加發送過程的日志給email通知中,所以,只能保存到日志中,如果需要了解email的交互過程,請到日志文件中查看  
        appendLog "退出時間到發送email的時間:$(date +%Y-%m-%d/%R:%S)\n使用mailx發送emial通知交互如下:\n\n${mailInfo}"  
    fi  

    exit $exitCode  
}  

# 追加日志  
function appendLog(){  
    echo -e "${1} \n" >> $shLogPath  
}  

if [ ! -e "${backupRoot}" ];then  
    appendLog "備份根目錄 ${backupRoot} 不存在,已創建"  
    mkInfo=$(mkdir -p $backupRoot 2>&1)  

    if [ "$?" -ne "0" ];then  
        appendLog "嘗試創建備份目錄 ${backupRoot}失敗:${mkInfo}"  
        myExit 1  
    fi  

elif [ ! -d "${backupRoot}" ];then  
    appendLog "備份根目錄路徑雖然存在,但是它不是目錄,中止:${backupRoot}"  
    myExit 2  
fi  

#今天的備份目錄  
todayRoot="${backupRoot}$(date +%Y%m%d%H)/"  

if [ ! -e "${todayRoot}" ];then  
    mkInfo=$(mkdir $todayRoot 2>&1)  

    if [ "$?" -ne "0" ];then  
        appendLog "嘗試創建本輪的備份目錄 ${todayRoot} 失敗,中止:${mkInfo}"  
        myExit 3  
    fi  
fi  

appendLog "今天的備份目錄:${todayRoot}"  
ver=$(mysql --version 2>&1)  

if [ "$?" -ne "0" ];then  
    appendLog "測試mysql的版本時出錯,中止,出錯信息:${ver}"  
    myExit 4  
fi  

ver=$(mysqldump -V 2>&1)  

if [ "$?" -ne "0" ];then  
    appendLog "測試mysqldump命令出錯,請安裝,中止,出錯信息:${ver}"  
    myExit 5  
fi  

ver=$(tail --version 2>&1)  

if [ "$?" -ne "0" ];then  
    appendLog "測試tail命令的版本時出錯,中止,出錯信息:${ver}"  
    myExit 41  
fi  

ver=$(tar  --version 2>&1)  

if [ "$?" -ne "0" ];then  
    appendLog "測試tar命令的版本時出錯,中止,出錯信息:${ver}"  
    myExit 42  
fi  

databases=$(mysql --host="127.0.0.1" --user="${mysqlBackupUser}"  --password="${mysqlBackupPwd}" --execute="show databases;"  --silent --skip-column-names --unbuffered 2>&1)  

if [ "$?" -ne "0" ]; then  
    appendLog "嘗試使用配置信息列舉mysql的數據庫名時出錯,中止:${databases}"  
    myExit 6  
else  
    appendLog "全部的數據庫名稱列表如下:\n ${databases}"  
fi  


for database in $databases; do  
    # 匹配時不區分大小寫  
    echo $notBackupDatabases|grep -i "(${database})" >/dev/null  

    # 屬于不需要備份的庫  
    if [ "$?" -eq "0" ];then  
        appendLog "數據庫 ${database} 被指定不需要備份,跳過"  
        continue  
    fi  

    databaseRoot="${todayRoot}${database}/"  

    if [ ! -e "${databaseRoot}" ];then  
        mkInfo=$(mkdir $databaseRoot 2>&1)  

        if [ "$?" -ne "0" ];then  
            appendLog "嘗試創建數據庫 ${databaseRoot} 的目錄失敗,中止:${mkInfo}"  
            myExit 7  
        fi  
    fi  


    tables=$(mysql --host="127.0.0.1" --user="${mysqlBackupUser}"  --password="${mysqlBackupPwd}" --execute="show tables from \`${database}\`;"  --silent --skip-column-names --unbuffered 2>&1)  

if [ "$?" -ne "0" ]; then  
    appendLog "嘗試使用配置信息列舉mysql的數據庫 ${database} 表的列表時出錯,中止:${tables}"  
    myExit 8  
else  
    appendLog "${database}數據庫表的全部列表如下:\n ${tables}"  
fi  

    for table in $tables; do  
        sqlPath="${databaseRoot}${table}.sql"  
        timeStart="開始dump時間點: $(date +%Y-%m-%d/%R:%S)"  
        dumpInfo=$(mysqldump --host="127.0.0.1" --user="${mysqlBackupUser}" --password="${mysqlBackupPwd}" --dump-date --comments --quote-names --result-file="${sqlPath}" --quick  --databases "${database}" --tables "${table}" 2>&1 )  
        timeEnd="完成dump時間點: $(date +%Y-%m-%d/%R:%S)"  

        if [ "$?" -ne "0" ];then  
            appendLog "嘗試導出數據庫 ${database}的表 ${table} 失敗,中止:${dumpInfo}"  
            myExit 9  
        else  
            appendLog "導出數據庫 ${database}的表 ${table} 到 ${sqlPath} 成功:${dumpInfo}; 耗時: 從 ${timeStart} 至 ${timeEnd}"  

            tail --lines=10 "${sqlPath}" |grep "\-\- Dump completed" 2>&1 > /dev/null  

            if [ "$?" -ne "0" ];then  
                appendLog "沒有發發現內容中的 'Dump completed' 正常完成標志字符,請檢查dump文件${sqlPath},請登錄ssh查看此文件是否備份成功"  
            else  
                appendLog "檢測到備份文件內容中的'Dump completed'標志字符,dump文件${sqlPath}應該備份成功了"  
            fi  

        fi  

    done  

done  

appendLog "\n ------數據庫備份全部完成------\n"  

# 開始壓縮,把壓縮放到備份結束是防止壓縮時間過長,如果出現鎖表,會影響網站運行  
sqls=$(ls --almost-all --ignore-backups --indicator-style=slash -1 ${todayRoot}*/*.sql 2>&1)  

for path in $sqls; do  
    #路徑中包含了絕對路徑,tar命令還需要改進  
    sqlDir=$(dirname $path)  
    sql=$(basename $path)  
    tarInfo=$(tar --create --remove-files --bzip2 --absolute-names --directory="${sqlDir}"   --add-file="${sql}" --file="${path}.tar.bz2")  

    if [ "$?" -ne "0" ];then  
        appendLog "壓縮并刪除${path}文件時出錯:\n${tarInfo}"  
    else  
        appendLog "已壓縮并刪除${path}"  
    fi  
done  

appendLog "------完成壓縮操作-----"  
#開始清理大于x天的備份  

daysDir=$(ls --almost-all --ignore-backups --indicator-style=slash -1 "${backupRoot}" 2>&1)  

for bkDir in $daysDir;do  
    bkDir="${backupRoot}${bkDir}"  

    if [ ! -d "${bkDir}" ];then  
        appendLog "準備刪除過期的備份操作時,因為${bkDir}不是一個目錄,跳過"  
        continue  
    fi  

    dirName=$(basename $bkDir)  
    #test  
    echo $dirName | grep -P "^\d{10}$" 2>&1 >/dev/null  

    if [ "$?" -ne "0" ];then  
        appendLog "準備刪除過期備份目錄時,檢測到待刪除目錄名不是10位數字,跳過:${bkDir}"  
        continue  
    fi  

    outDay=$(date --date="-${deleteRootOutDays}day" "+%Y%m%d00")  

    #如果文件時間小于這個過期時間那么就強制刪除整個目錄  
    if [ "${dirName}" -lt "${outDay}" ];then  
        rmInfo=$(rm --force --preserve-root --recursive "${bkDir}" 2>&1)  
        appendLog "發現一個過期備份目錄 ${bkDir},已經超過 ${deleteRootOutDays} 天,也就是小于${outDay}就會被刪除 ,被強制刪除狀態(0為成功):${?} ${rmInfo};"  
    fi  

done  

appendLog "------完成清理過期備份文件夾操作----"  
appendLog "空間使用情況如下:\n $(df -h)"  
appendLog "當前備份文件占用空間情況:\n $(du -hs ${todayRoot})"  
myExit 0  </pre> 


 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!