@梁宇轩9年前

01/27
18:59
技术笔记

Linux主機的自動備份腳本

零、前言

感覺已經好久沒有更新過部落格了,上一篇文章似乎已經是去年8月的事情了,看到一些人的更新頻率真是爲自己感到汗顏,真是擔心有人以爲這個站已經不再維護了呢。

最近由於某些原因導致經常接觸Linux,也寫了幾個自動化腳本,突然就想起之前編寫的這個自動備份腳本,自我感覺還是不錯的,剛剛重新寫了一下,變得通用了一點。

一、前期準備

我所採用的策略是打包備份後發送郵件到郵箱,畢竟現在那些提供商都準備了這麼大的空間,感覺不用可惜了。

所以你需要的是

1.定時執行任務的方式,例如虛擬空間的時間守護任務,或者是VPS的corn。

2.一個發送郵件的方式,例如Linux自帶的mail命令,或者是mutt命令,或者是利用PHP庫透過SMTP服務發送郵件。

3.一個可以容納中間文件的空間,大約是最終文件的大小再加上最大的塊的中間文件。

其中的1和2是必須的,不然基礎的東西都沒辦法做到。如果是3難以達成,可以考慮修改腳本來減少空間需求,不過至少還是有最大的塊的中間文件的容納能力,不然就有點麻煩了。

二、備份原理

1.文件使用tar命令打包,使用gzip壓縮。

2.數據庫使用mysqldump命令打包。

3.最後使用tar命令打成一個大包。

三、腳本配置

#!/bin/bash

######################################
# This shell has been used in lyx.es.#
#       Written by YuxuanLiang.      #
######################################

################################
#         User Config          #
################################

# working path
# Example: WORKING="/home/backup"
WORKING=""

# main path
# Example: MAIN="/home"
#          MAINNAME="public_html"
# means the webside root is "/home/public_html"
MAIN=""
MAINNAME=""

# exclude folder in main path
# Example: EXCLUDE=("cgi-bin")
EXCLUDE=()

# main SQL's infmation
# Example: MYSQL="database_name"
#          ADDRESS="" # (optional) if the database's address is not default, put it here
#          USER="username"
#          PASS="password"
MYSQL=""
ADDRESS=""
USER=""
PASS=""

# blocks path
# Example: BLOCK="/home/public_html"
#          BLOCKS=("blog")
# means a block can be found in ${BLOCK}/${BLOCKS[0]}
# Note: if ${MAIN}/${MAINNAME} equals ${BLOCK}, blocks will be also excluded while main backup is processing
BLOCK=""
BLOCKS=()

# blocks' SQL's infmation
# Example: MYSQLS=("database_name1" "database_name2")
#          ADDRESSES=("") # (optional) if the database's address is not default, put it here
#          USERS=("username1" "username2")
#          PASSES=("password1" "password2")
MYSQLS=()
ADDRESSES=()
USERS=()
PASSES=()

# the way to send email
# Example: function send {
#          	echo "This is my webside backup at $1" | mutt YOUREMAIL -s "Webside Backup" -a backup$1.tar.gz
#          }
function send {
}

# if debug mode opens
# Example: DEBUG=0
DEBUG=0

配置的部分都很簡單,將這些代碼放在腳本的最前面就可以了。

不過還有一件事情需要提一下,使用Windows編輯的上傳後會出現

/bin/bash^M: bad interpreter: No such file or directory

這樣的錯誤,這是因爲Windows下和Linux下的換行方式不同。我個人的解決方式是使用Submlime Text的十六進制顯示中替換0d0a爲0a,然後繼續用Sublime Text來編輯,就不會出現問題了。

四、腳本主體

因爲裏面的內容略複雜,所以請在确认修改的影响的前提下謹慎編輯,以防数据出现丢失。

################################
#         Main Program         #
#DO NOT rewrite the followings.#
################################

# Initiating
DATE=`date +%Y%m%d%H%M%S`
test $DEBUG -eq 1 && T="z" || T=""
cd ${WORKING}
test $DEBUG -eq 1 && echo "--Pack log start--"

# Main webside backup
TEMP="file$DATE.tar.gz"
for S in "${EXCLUDE[@]}"
do
	EXCL="${EXCL}--exclude=${MAINNAME}/${S} "
done
if [ "${MAIN}/${MAINNAME}" = "${BLOCK}" ]; then
	for S in "${BLOCKS[@]}"
	do
		EXCL="${EXCL}--exclude=${MAINNAME}/${S} "
	done
fi
tar -${T}cvf file$DATE.tar.gz ${EXCL} -C "${MAIN}" ${MAINNAME}

if [ ${MYSQL} ]; then
	TEMP="${TEMP} data$DATE.sql.gz"
	test ${ADDRESS} && TMP="--host=${ADDRESS}" || TMP=""
	mysqldump --user=${USER} --password=${PASS} $TMP ${MYSQL} | gzip > data$DATE.sql.gz
fi

tar -${T}cf main$DATE.tar.gz ${TEMP}
rm ${TEMP}

# Blocks backup
for (( I=0; I<${#BLOCKS[@]}; I++ ))
do
	TEMP="file$DATE.tar.gz"
	tar -${T}cvf file$DATE.tar.gz -C ${BLOCK} ${BLOCKS[$I]}
	if [ ${MYSQLS[$I]} ]; then
		TEMP="${TEMP} data$DATE.sql.gz"
		test ${ADDRESS} && TMP="--host=${ADDRESSES[$I]}" || TMP=""
		mysqldump --user=${USERS[$I]} --password=${PASSES[$I]} $TMP ${MYSQLS[$I]} | gzip > data$DATE.sql.gz
	fi

	tar -${T}cf ${BLOCKS[$I]}$DATE.tar.gz ${TEMP}
	rm ${TEMP}
done

# Send e-mail & Clean temp file
TEMP="main$DATE.tar.gz"
for (( I=0; I<${#BLOCKS[@]}; I++ ))
do
	TEMP="$TEMP ${BLOCKS[$I]}$DATE.tar.gz"
done

tar -${T}cf backup$DATE.tar.gz ${TEMP}
send $DATE
rm backup$DATE.tar.gz $TEMP

# Print log
test $DEBUG -eq 1 && echo $'--Pack log end--\n\n'
echo "This cron started at $DATE, is ending at `date +%Y%m%d%H%M%S`."

if [ ${DEBUG} -eq 1 ]; then
	echo "[Debug] The following is file(s) and folder(s) in working path."
	ls
fi

五、其他配置

還記得文章開始提到的三個條件嗎?其中的第二個就提到了使用PHP透過SMTP服務發送郵件,我就是用這種方法的,那是因爲我用的這個空間在使用時間守護作業的時候是無法透過命令發送郵件的,調用PHP的mail函數也沒有辦法使用,所以只能用這種方式來發郵件了。

SMTP發送實在是不想自己編了,所以就選擇了PHPMailer這個庫,不要重複發明輪子嘛。下面粘一段代碼上來,相信各位都看得懂的了。

<?php
	require_once('./class.phpmailer.php');
	$_GET['DATE'] = ereg_replace("\n", "", $_GET['DATE']);

	$mail = new PHPMailer();
	$mail->SetLanguage("zh", "./");

	$mail->IsSMTP();
	$mail->Host = "";
	$mail->Port = ;
	$mail->SMTPAuth = true;
	$mail->Timeout = 300;

	$mail->CharSet = "UTF-8";
	$mail->Encoding = "base64";

	$mail->Username = "";
	$mail->Password = "";
	$mail->Subject = "網站備份";

	$mail->From = "";
	$mail->FromName = "";

	$mail->AddAddress("");

	$mail->AddAttachment("backup" . $_GET['DATE'] . ".tar.gz");
	$mail->Body = "此郵件附件是於" . $_GET['DATE'] . "的網站備份。";

	if(!$mail->Send())
		echo "郵件發送失敗,錯誤原因:" . $mail->ErrorInfo;
	else
		echo "郵件發送成功!";
	echo "\n";
?>

高亮的幾行需要自己填寫一下,使用的變量名和函數名如此簡單,相信大家都能理解。如果使用這種方式,那麼function send可以定義爲

function send {
	php send.php DATE=$1
}

六、尾聲

去重新看了一下之前寫的文章,感覺更新的時間似乎可以組成不嚴格的等差數列了,畢竟是學生黨,時間明顯不夠用。只有寒暑假才写写文章放上部落格,感觉自己也有点感到可惜,希望今年有更多机会来更新这里啦。

最後提供一下兩個腳本的下載地址(zip),即将失传的字符画也会出现在里面哦(虽然不是很棒)。

Linux主機的自動備份腳本

  1. 艾瑪,之前一直想找一個類似的腳本,但是一直沒找到,根本就沒想過要自己編一個,所以我用的是DropBox的linux客戶端備份VPS…
    這個腳本保存備用~
    ====
    快來幫忙開發後端…Orz

    回复
    1. 對了,備份數據庫的那一部分可以修改一下,默認備份全部數據庫…
      比如我有100個數據庫,全部填上去就有點蛋疼了。。。

      回复
      1. 梁宇軒 文章作者

        因為我的網站是分Part的,所以數據庫都是不相關的,又想一個包之中的文件也是分Part的,所以就這樣寫咯~如果是簡單的備份的話就兩部分就可以啦,很簡單的。
        我是想著某提供商的郵箱大得逆天,那麼每天發點不重複的東西也無所謂啦,呵呵呵~~~

        回复