生活随笔
收集整理的这篇文章主要介绍了
linux下简单的备份的脚本 2 【转】
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26807463&id=4577034
之前写过 linux下简单的备份的脚本 , 最开始一直用着, 后来觉得有必要改进下它了, 不管是从操作方式上还是工作方式上。有这样的想法是因为一次备份引起的。 我经历过磁盘损坏的痛苦, 花了1500元才勉强将数据拯救回来, 于是导致我对备份要求更加高了, 我期望尽量每周备份, 期望备份的目的地是当前系统的完整镜像,也就是说我能够从备份盘启动,且启动后
系统的操作方法以及文件和当前的一模一样,每周我只需要增量备份当前的修改的备份盘,这样就安全了很多。于是就有了下面的备份脚本(我不喜欢造轮子,但是在linux下没有现成的适合我的)
NOTE: 当前还没有加入自动镜像系统,所以如果想镜像系统,那么可以手动这样操作, 准备一块大于当前系统盘的移动盘,
分区,注意分区的结构尽量和系统的一模一样, 然后格式化,文件系统也尽量相同, 然后就可以备份了 备份的时候主要有些
目录需要跳过,比如sys dev proc等等,需要跳过的目录可以在backup程序了面设置!
这是脚本程序:
点击(此处)折叠或打开
#!/bin/bash# This program is free software; you can redistribute it and/or# modify it under the terms of the GNU General Public License as# published by the Free Software Foundation; either version 2 of# the License, or (at your option) any later version.# # This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU General Public License for more details.# Author: rongp# email: rongpmcu#gmail.com# Date: 2014/10/26# 备份程序# 特点:# 主要支持unix类系统下, 支持符号链接# 支持增量备份# 支持网络备份(由于基于rsync, 很容易加入该功能,但暂时没加入)# 文件名支持空格 但是不能出现含有@#@的文件名# 支持备份每次的更新,方便用于人工操作失误后的修复# 支持添加规则用于剔除某些文件 格式参考rsync的PATTERN部分 SHELL=/bin/bashbackup_cfg_path=/etcbackup_cfg=$backup_cfg_path/backup.cfgdb_path=db_pathname=inc_path= XECHO=1 _help() { echo -e "$0 [option]\n"\ "\tOption:\n"\ "\t-h show this help.\n"\ "\t-i perform the installation, and you should use this option\n"\ "\t before using the backup to do something else.\n"\ "\t-u perform the un-installation.\n"} help() { echo -e "Command action\n"\ "\th show this help.\n"\ "\ta add any file that you want to backup to the database.\n"\ "\td delete any file that you no longer want from the database.\n"\ "\tb start backup.\n"\ "\tbf assume \"yes\" as answer to all prompts and run non-interactively.\n"\ "\tn perform a trial backup with no changes made.\n"\ "\tp print the file record.\n"\ "\tc do some configurations, such as, modifying the path to the\n"\ "\t database or to the incremental backup directory.\n"\ "\ts show the current configuration.\n"\ "\ti perform the installation, and you should use this option\n"\ "\t before using the backup to do something else.\n"\ "\tu perform the un-installation.\n"\ "\tq quit"} color_echo(){ case "$1" in g) shift echo -e "\033[32m"$@"\033[0m" ;; gn) shift echo -e -n "\033[32m"$@"\033[0m" ;; r) shift echo -e "\033[31m"$@"\033[0m" ;; y) shift echo -e "\033[33m"$@"\033[0m" ;; yn) shift echo -e -n "\033[33m"$@"\033[0m" ;; *) shift echo $@ ;; esac} XECHO(){ if [ "$XECHO" = 1 ]; then echo $@ fi} check_src_dst(){ if ! test -e "$1" || ! test -e "$2"; then color_echo r "$1" or "$2" does not ignore return 2 fi local src_part1=`df "$1" | cut -d ' ' -f 1` local src_part2=`df "$2" | cut -d ' ' -f 1` local nsrc_inode=`ls -lid "$1" | cut -d ' ' -f 1` local ndst_inode=`ls -lid "$2" | cut -d ' ' -f 1` XECHO nsrc_inode:$nsrc_inode ndst_inode:$ndst_inode if [ "$src_part1" != "$src_part2" ]; then return 1 fi if [ "$nsrc_inode" = "$ndst_inode" ]; then color_echo r "$src is equivalent to $dst. ignore it!" return 2 fi if [ ! -e $db_pathname ]; then return 1 fi while read -r tsrc tdst tex_src; do tsrc="${tsrc//@#@/ }" tdst="${tdst//@#@/ }" tex_src="${tex_src//@#@/ }" XECHO tsrc:"$tsrc" tdst:"$tdst" osrc_inode=`ls -lid "$tsrc" | cut -d ' ' -f 1` odst_inode=`ls -lid "$tdst" | cut -d ' ' -f 1` XECHO osrc_inode:$osrc_inode odst_inode:$odst_inode if [ "$nsrc_inode" = "$osrc_inode" -a "$ndst_inode" = "$odst_inode" ]; then if [ ${1:((${#1}-1))} = '/' -a ${tsrc:((${#tsrc}-1))} != '/' ] \ || [ ${1:((${#1}-1))} != '/' -a ${tsrc:((${#tsrc}-1))} = '/' ]; then #/home and /home/ is very echo -n ""; else return 0 fi fi done < $db_pathname return 1 } extract_src_dst(){ XECHO "extract src dst from $1" src="${1%#*}" dst="${1#$src}" dst="${dst#\#}" XECHO "src: $src" XECHO "dst: $dst" if [ "$src" = "" -o "$dst" = "" ]; then return 1 else return 0 fi} fix_path(){ local srcpath="$1" if [ "${srcpath:0:1}" = '/' ]; then echo $srcpath elif [ "${srcpath:0:2}" = './' ]; then echo `pwd`/${srcpath:2} else echo `pwd`/$srcpath fi} insert_new_item(){ XECHO add item src:"$1" dst:"$2" exclude:"$3" tmp1="${1// /@#@}" tmp2="${2// /@#@}" tmp3="${3// /@#@}" echo "$tmp1" "$tmp2" "$tmp3" >> $db_pathname return $?} parse_item(){ if ! extract_src_dst "$1"; then color_echo r "src:$src or dst:$dst is illegal!" return 1 fi src=`fix_path "$src"` dst=`fix_path "$dst"` XECHO after fixed, src:"$src" XECHO after fixed, src:"$dst" return 0} do_add() { local item color_echo g "Enter the mode of adding files! Some patterns are available, as follows:" color_echo g "eg: /home/#/tmp/ means we want to backup the whole things which " color_echo g "are under home directory to /tmp directory." color_echo g "eg: /home/#/tmp/:/etc/#/tmp/ means we want to backup the whole " color_echo g "things which are under the home directory and the /etc/ directory " color_echo g "to the /tmp directory, you can append any item with ':'." color_echo r "Note: /home and /home/ are quite different, because /home just means " color_echo r "/home itself while /home/ means the whole contents of /home." read -p "Please type in file items: " items items="`echo "$items" | sed "s/'//g"`" flag=0 while [ $flag = 0 ]; do item=${items%%:*} items=${items#$item:} ex_src="" if [ "$items" = "$item" ]; then flag=1 fi if parse_item "$item"; then check_src_dst "$src" "$dst" ret=$? if [ "$ret" = 0 ]; then color_echo y "Warning! ""$src#$dst"" is already existed! do not re-submit!" continue elif [ "$ret" = 2 ]; then continue fi read -p "Would you like to add some excluding conditions to $src: (y/n)[n] " yn if [ "$yn" = y ]; then color_echo r "Note: this is an expert mode, and we don't check your pattern" color_echo r "is valid or not. Some patterns are available, as follows:" color_echo r "eg: if your src directory is /home, and your want to exclude" color_echo r "the directory /home/rongp, then you should type in \"rongp\"." color_echo r "eg: if your src directory is /home, and your want to exclude" color_echo r "the directory /home/rongp and /home/test, then you should" color_echo r "type in \"rongp:test\", and you can append any item with ':' ." read -p "Please type in paths to the excluding files: " exitem ex_src="$exitem" fi if insert_new_item "$src" "$dst" "$ex_src"; then echo ""$src"#"$dst" add successed!" else echo ""$src"#"$dst" add failed!" fi else read -p "skip it? Yy/Nn:[n] " yn if [ "$yn" = "y" -o "$yn" = "Y" ]; then continue fi return 1 fi done return 0 } get_choices(){ local total_line=`wc -l $db_pathname | cut -d ' ' -f 1` select_tab= color_echo g "Enter the mode of "$1"! some patterns are available, as follows:" color_echo g "eg: 1-3 means select no 1 2 3 item" color_echo g "eg: 1:3:5 means select no 1 3 5 item" color_echo g "you can append any no with ':' or '-', but don't mix use it." color_echo g "no 0 means select all." do_print read -p "Please type in the number: " NO if [ "${NO/-/ }" != "$NO" ]; then num_tab=(${NO//-/ }) [ ${#num_tab[@]} -gt 2 ] && \ echo "Select failed, argument $NO is illegal!" && return 1 num0=${num_tab[0]} num1=${num_tab[1]} XECHO num0:$num0 num1:$num1 if [ -z "${num0//[0-9]/}" -a "$num0" -le "$total_line" -a "$num0" -gt "0" ]\ && [ -z "${num1//[0-9]/}" -a "$num1" -le "$total_line" -a "$num1" -gt "0" ]\ && [ "$num0" -lt "$num1" ]; then select_tab=(`seq $num0 $num1`) else echo "Select failed, argument $NO is illegal!" && return 1 fi elif [ "${NO/:/ }" != "$NO" ]; then for num in ${NO//:/ } do if [ -z "${num//[0-9]/}" ]&&[ "$num" -le "$total_line" ]\ &&[ "$num" -gt "0" ]; then continue else echo "Select failed, argument $num is illegal!" && return 1 fi done j=0 for i in ${NO//:/ } do select_tab[j]=$i ((j++)) done else if [ "$NO" = 0 ]; then select_tab=(`seq 1 $total_line`) elif [ -z "${NO//[0-9]/}" ]&&[ "$NO" -le "$total_line" ]\ &&[ "$NO" -gt "0" ]; then select_tab[0]=${NO} else echo "Select failed, argument $NO is illegal!" && return 1 fi fi return 0} do_del() { if ! get_choices "deleting files"; then return 1 fi local total_num=${#select_tab[@]} if [ "$total_num" = 1 ]; then nums=${select_tab[0]}d elif [ "$total_num" = 2 ]; then nums=${select_tab[0]},${select_tab[1]}d else for ((i=0; i<$total_num; ++i)) do nums+="${select_tab[i]}d;" done fi sed -i "$nums" $db_pathname >/dev/null 2>&1 [ "$?" = 0 ] && echo "$NO delete successed!" || echo "$NO delete failed, delete failed!"} do_print(){ [ ! -s $db_pathname ] && color_echo y "Warning, no record found!" && return 1 echo " no source destination action" cat -n $db_pathname | sed 's/@#@/ /g'} check_in_select_tab(){ local i for ((i=0; i<${#select_tab[@]}; ++i)) do XECHO $1:select_tab[$i]:${select_tab[i]} if [ "${select_tab[i]}" = "$1" ]; then return 0 fi done return 1} do_backup(){ local ex_file=`mktemp` local fake="${1/fake/-n}" local yes="${1/yes/y}" [ ! -f "$db_pathname" ] && color_echo r "$db_pathname does not exist!" && return 1 if ! get_choices "backup"; then return 1 fi local i=0 local k=0 while read -r src dst ex_src; do if check_in_select_tab $((i+1)); then XECHO "$i in select table" src="${src//@#@/ }" dst="${dst//@#@/ }" XECHO src:$src dst:$dst ex_src:$ex_src ex_file:$ex_file src_tab[k]="$src" dst_tab[k]="$dst" ex_src_tab[k]="$ex_src" ((k++)) fi ((i++)) done < $db_pathname for ((j=0; j<$k; ++j)) do echo src:${src_tab[j]} dst:${dst_tab[j]} ex_src:${ex_src_tab[j]} src="${src_tab[j]}" dst="${dst_tab[j]}" ex_src="${ex_src_tab[j]}" echo "$ex_src" | awk -F ':' '{for (i=1;i<=NF;++i)print $i}' | sed 's/@#@/ /g' > $ex_file if [ "$src" = "/" ]; then tmpsrc=$(blkid `mount | grep "/ " | cut -d ' ' -f 1` | awk -F "\"" '{print $2}') else tmpsrc="$src" fi if [ "$dst" = "/" ]; then tmpdst=$(blkid `mount | grep "/ " | cut -d ' ' -f 1` | awk -F "\"" '{print $2}') else tmpdst="$dst" fi color_echo g "We will start backup from " color_echo r "$src" color_echo g to color_echo r "$dst" color_echo g "with excluding file or directory" color_echo r "${ex_src//@#@/ }" color_echo gn "continue or not? y/n: " if [ "$yes" = y ]; then yn=y else read yn fi if [ "$yn" = y ]; then echo Start backup "$src" to "$dst" with excluding file or directory "$ex_src" ( flock -x 200 rsync -avzrtopg $fake --progress --delete --exclude-from=$ex_file \ "$src" "$dst" --backup --backup-dir=$inc_path/$(date +%Y-%m-%d_%H:%M:%S_$(basename ${tmpsrc})_$(basename $tmpdst)) ) 200>/var/lock/abc echo Backup $src to $dst with excluding file or directory $ex_src else echo Skip backup $src to $dst with excluding file or directory $ fi done } get_answer(){ local ret if [ "$4" != "" ]; then tmpbackup="$4" else tmpbackup=backup.cfg.bak fi while : do read -p "Type in $1 path of the backup(default is $2, q for exit): " ans_tmp if [ "$ans_tmp" = q ]; then ret=1 break elif [ "$ans_tmp" != "" ]; then if [ ! -d "$ans_tmp" ]; then echo "$1: $ans_tmp is invalid!" read -p "Would you like to create it now? y/n [y]: " yn if [ "$yn" = y ]; then mkdir -p $ans_tmp else continue fi fi sed -i "s,$3.*,$3$ans_tmp,g" $tmpbackup ret=$? break else ans_tmp="$2" ret=0 break fi done return $ret} already_install(){ if load_cfg $backup_cfg s; then XECHO "already install" return 0 #has install fi return 1} do_install(){ color_echo g start install if already_install; then color_echo y "We check that you have already installed, you should" color_echo yn "uninstall first, would you want to uninstall it first?y/n[n] " read yn if [ "$yn" != y ]; then color_echo g install color_echo r install return 1 else do_uninstall fi fi cp -f backup.cfg backup.cfg.bak load_cfg backup.cfg.bak s if [ "$?" = 1 ]; then exit fi if ! get_answer "executable file backup" "$bin_path" "INSTALL_PATH=";then color_echo g install color_echo r install return 1 fi install_path=$ans_tmp color_echo g install path is $install_path if ! get_answer "database" "$db_path" "DB_PATH=";then color_echo g install color_echo r install return 1 fi db_path=$ans_tmp color_echo g database path is $db_path if ! get_answer "incremental backup" "$inc_path" "INCREMENTAL_BACKUP_PATH=";then color_echo g install color_echo r install return 1 fi inc_path=$ans_tmp color_echo g incremental backup path is $inc_path echo who=`whoami` cp backup $install_path color_echo g install backup to $install_path ret=$? mv backup.cfg.bak $backup_cfg color_echo g install $backup_cfg ret=$((ret+$?)) mkdir -p $db_path color_echo g install $db_path ret=$((ret+$?)) mkdir -p $inc_path color_echo g install $inc_path ret=$((ret+$?)) ln -s $db_path $inc_path/db color_echo g install $inc_path/db ret=$((ret+$?)) color_echo g install if [ $ret -gt 0 ]; then color_echo r install [ -e $bin_path/backup ] && rm_print $bin_path/backup [ -e $backup_cfg ] && rm_print $backup_cfg [ -e $inc_path/db ] && rm_print $inc_path/db && rm_print -rf $inc_path [ -e $db_pathname ] && rm_print $db_pathname rm_print -d $db_path return 1 fi echo echo color_echo y "The installation work is done, and you can remove this package now!" color_echo y "Note: you should put the executable file \"backup\"" color_echo y "into \$PATH and you need to get \"root\" privileges to execute it." color_echo y "for example, you can execute it like this in ubuntu: sudo backup" return 0} rm_print(){ color_echo g remove $@ eval rm $@} do_uninstall(){ XECHO "Perform the un-installation." color_echo g perform the un-installation... if ! load_cfg $backup_cfg; then color_echo g uninstall fi [ -e $bin_path/backup ] && rm_print $bin_path/backup [ -e $backup_cfg ] && rm_print $backup_cfg [ -e $inc_path/db ] && rm_print $inc_path/db && rm_print -rf $inc_path [ -e $db_pathname ] && rm_print $db_pathname rm_print -d $db_path color_echo g uninstall color_echo g uninstall } load_cfg(){ if [ ! -e "$1" ]; then [ "$2" != "s" ] && color_echo r "Error, we can't find the configure file $1, exit now!" return 1 fi bin_path=`sed -n 's/INSTALL_PATH=\(.*\)/\1/p' $1` db_path=`sed -n 's/DB_PATH=\(.*\)/\1/p' $1` db_pathname=$db_path/backup.db inc_path=`sed -n 's/INCREMENTAL_BACKUP_PATH=\(.*\)/\1/p' $1` if [ ! -d "$inc_path" ]; then [ "$2" != "s" ] && color_echo r Load configuration file your should [ "$2" != "s" ] && color_echo r check the directory $db_pathname is valid or return 2 fi XECHO database path is $db_path XECHO database file path is $db_pathname XECHO incremental backup path is $inc_path return 0} show_configure(){ color_echo g executable backup is in $bin_path color_echo g database directory is in $db_path color_echo g incremental backup directory is in $inc_path} do_modify_inc_backup_path(){ if ! get_answer "incremental backup" "$inc_path" \ "INCREMENTAL_BACKUP_PATH=" $backup_cfg;then return 1 fi inc_path=$ans_tmp XECHO incremental backup is $inc_path return 0} do_configure(){ color_echo g [1] modify incremental backup path color_echo g [2] ... read -p "Please type in the no which you are expecting to: " no if [ "$no" = 1 ]; then do_modify_inc_backup_path else color_echo r Unsupported fi} backup_start(){ if ! load_cfg $backup_cfg; then exit fi while : do read -p "Command (h for help): " cmd case "$cmd" in a) do_add ;; d) do_del ;; p) do_print ;; c) do_configure ;; b) do_backup ;; bf) do_backup yes ;; n) do_backup fake ;; s) show_configure ;; i) do_install ;; u) do_uninstall exit ;; q) break ;; h | *) help ;; esac done} username=`echo $USER` if [ "$username" != root ]; then color_echo r "Error, you need to have \"root\" privileges to execute this program." exitfi if [ "$1" = "-i" ]; then if ! do_install; then color_echo y "Sorry, We can't continue any more. Exit now!" fi exitelif [ "$1" = "-u" ]; then do_uninstall exitelif [ "$1" = "-h" ]; then _help exitfi if [ ! -e $backup_cfg ]; then color_echo r "$backup_cfg does not exist! " read -p "You need to install the backup first. perform the installation? y/n?[y]: " yn if [ "$yn" != n ]; then do_install else echo Sorry, we can\'t continue any more. Exit fi exitfi backup_start
这是配置文件
点击(此处)折叠或打开
################################################################AUTHOR=rongpEMAIL=rongpmcu@gmail.comVERSION=1.0 INSTALL_PATH=/usr/bin/DB_PATH=/var/lib/backup/INCREMENTAL_BACKUP_PATH=/var/lib/backup/incr_backup
git路径:git@bitbucket.org:rongpmcu/backup-script-shell.git
【作者】张昺华 【出处】http://www.cnblogs.com/sky-heaven/ 【博客园】 http://www.cnblogs.com/sky-heaven/ 【新浪博客】 http://blog.sina.com.cn/u/2049150530 【知乎】 http://www.zhihu.com/people/zhang-bing-hua 【我的作品---旋转倒立摆】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【我的作品---自平衡自动循迹车】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2 【新浪微博】 张昺华--sky 【twitter】 @sky2030_ 【facebook】 张昺华 zhangbinghua 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
总结
以上是生活随笔为你收集整理的linux下简单的备份的脚本 2 【转】的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。