配置文件智能的備份和還原
運用場景:
每當我們為很多安裝同樣的機器升級或者更新服務時,要備份配置文件中的某一行或者多行,或者一個數據塊或者多個數據塊,和服務升級、更新完後,再把對應的備份數據重新寫回新的配置文件中;在大批量的服務器中操作,會浪費很多的時間和精力,以下腳本就是用來完成類似的事情。
主要功能有:
1.備份指定的一行或者多行,一個塊或者多個塊
2.備份指定的單個文件
3.還原所有部分備份和所有備份
4.配置文件精確定位插入【正則匹配】
5.配置文件精確定位刪除
6.配置文件類似行後批量插入
服務的配置文件樣例:
- server.config:
- ####配置文件樣例:
- ser_max_connection=6000 #行
- ser_min_connection=10
- ser_time_out=60
- ser_time_spent=120
- server tcp_nodes{ ##塊
- ser_client_ip=ipv4
- ser_client_len=20*N
- ser_client_syn=yes
- ser_client_ack=yes
- }
以下是shell腳本的代碼實現,腳本主要是利用sed工具來完成配置編輯功能。此腳本是根據真實應用環境中改成通用版本,並沒有經過嚴格的測試,如果你想要用此腳本,還請根據自己的環境下,做嚴重的測試。如果你有更好的想法,請加入QQ群:63565867。
- #!/bin/bash
- #DianDian
- proconf=/usr/local/server/etc #要備份的主目錄,參數傳入的文件名和會這個路徑合並起來
- confpath=$proconf
- bkpath=/usr/local/src/bkconfig/part #備份文件中部分內容的保存目錄
- bkpath_whole=/usr/local/src/bkconfig/whole #備份整個文件的保存目錄
- handle_date=$(date "+%y%m%d%H%M")
- mkdir -p $bkpath $bkpath_whole
- FJ='^\+'
- FD='^\='
- ALLFILE=""
- function multidir(){ #dirname ##shell裡面的一個遞歸函數,用來獲得一個目錄下的所有文件【如果文件名中包括空格,可能會出錯】
- local dirs=$1
- local diri=0
- if [ ! -d $dirs ];then
- echo "$dirs is not a directory."
- exit 1
- fi
- local lsfile=$(ls -d $dirs/* 2>/dev/null)
- local dir_list=($lsfile)
- for((diri=0;diri<${#dir_list[@]};diri++)){
- if [ -d ${dir_list[$diri]} ];then
- multidir ${dir_list[$diri]}
- else
- ALLFILE="$ALLFILE ${dir_list[$diri]}"
- fi
- }
- }
- if [ "X$1" == "Xbackup" ];then
- num=0
- if [ "X$2" != "X" ];then
- OLD_IFS="$IFS"
- IFS="#"
- field=($2)
- IFS="$OLD_IFS"
- else
- echo -e "\033[31m Error \033[0m"
- exit 1
- fi
- SFS="+"
- F_CONF="$confpath/${field[0]}"
- B_CONF="$bkpath/${field[0]}"
- B_CDIR=$(dirname $B_CONF)
- if [ -e "$B_CONF" -a -s "$B_CONF" ];then
- echo -e "\033[31m Error $B_CONF exist and no empty. \033[0m"
- exit 1
- fi
- if [ ! -d $B_CDIR ];then
- mkdir -p $B_CDIR
- fi
- if [ -f "$F_CONF" ];then
- echo "backup @${field[0]}"
- while read line
- do
- ((num++))
- for((i=1;i<${#field[@]};i++)){
- if [[ ${field[$i]} =~ $FJ ]];then
- ST=${field[$i]#+}
- if [[ $line =~ ^$ST ]];then
- sed -n "$num,/}/p" $F_CONF | sed '1s/^/&+/' >> $B_CONF
- fi
- elif [[ ${field[$i]} =~ $FD ]];then
- ST=${field[$i]#=}
- STLine=${line%%=*}
- if [[ "$STLine" == "$ST" ]];then
- sed -n "${num}p" $F_CONF | sed '1s/^/&=/' >> $B_CONF
- fi
- else
- if [[ $line =~ ^${field[$i]} ]];then
- sed -n "${num}p" $F_CONF | sed '1s/^/&-/' >> $B_CONF
- fi
- fi
- }
- done < $F_CONF
- else
- echo -e "\033[31m Error:Skip ${field[0]} \033[0m"
- fi
- elif [ "X$1" == "Xrestore" ];then
- if [ "X$2" != "X" ];then
- List=(`ls -f $bkpath/$2 2>/dev/null`)
- else
- #List=(`ls -d $bkpath/* 2>/dev/null`)
- multidir $bkpath
- List=($ALLFILE)
- fi
- if [ "$List" == "" ];then
- echo -e "\033[31m restore:no valid file. \033[0m"
- fi
- for i in ${List[*]}
- do
- num=0
- B_CONF="$i"
- base=$(basename $i)
- if [ "$base" == "" -a -s $B_CONF ];then
- echo -e "\033[31m restore error @ $B_CONF \033[0m"
- continue
- fi
- F_CONF=$(echo $i | sed -n "s#$bkpath#$confpath#p")
- #F_CONF="$confpath/$base"
- echo -n "@ $F_CONF "
- if [ ! -f $F_CONF ];then
- echo -e "\033[31m restore error @ $F_CONF \033[0m"
- continue
- fi
- while read bconf
- do
- ((num++))
- TT=""
- Str=""
- if [[ $bconf =~ $FJ ]];then
- Str=$(sed -n -e "${num},/}/p" $B_CONF | sed '1s/^+//' | awk '{S=S"\\n"$0;}END{sub(/^../,"",S);printf("%s",S);}')
- TT="+"
- elif [[ $bconf =~ $FD ]];then
- Str=$(sed -n -e "${num}p" $B_CONF | sed '1s/^=//' | awk '{S=S"\\n"$0;}END{sub(/^../,"",S);printf("%s",S);}')
- TT="="
- elif [[ $bconf =~ ^- ]];then
- Str=$(sed -n -e "${num}p" $B_CONF | sed '1s/^-//' | awk '{S=S"\\n"$0;}END{sub(/^../,"",S);printf("%s",S);}')
- TT="-"
- else
- continue
- fi
- First=$(echo -e $Str | sed -n 1p)
- seek=0
- while read fconf
- do
- ((seek++))
- tmp_fconf=${fconf%%=*}
- tmp_first=${First%%=*}
- if [ "$tmp_fconf" == "$tmp_first" ];then
- if [ "$TT" == "+" ];then
- sed -i "${seek},/}/d" $F_CONF
- if [ $seek -ne 1 ];then
- sed -i "$[ ${seek} - 1 ]a$Str" $F_CONF
- else
- sed -i "${seek}a$Str" $F_CONF
- fi
- echo -n "$TT"
- TT=""
- break
- elif [ "$TT" == "=" ];then
- sed -i "${seek}s/.*/$Str/" $F_CONF
- echo -n "$TT"
- TT=""
- break
- elif [ "$TT" == "-" ];then
- sed -i "${seek}s/.*/$Str/" $F_CONF
- echo -n "$TT"
- TT=""
- break
- fi
- fi
- done < $F_CONF
- if [ "$TT" != "" ];then
- Err=$Err" $First\n"
- fi
- done < $B_CONF
- echo
- done
- if [ "$Err" != "" ];then
- echo -e "\n\033[33mError: $Err\033[0m"
- Err=""
- fi
- elif [ "X$1" == "Xinsert" ];then
- num=0
- snum=0
- n=1
- nn=0
- OLD_IFS="$IFS"
- IFS="#"
- if [ "X$2" != "X" ];then
- insert=($2)
- else
- echo -e "\033[31m Insert Error \033[0m"
- exit 1
- fi
- IFS="$OLD_IFS"
- if [ -f "$confpath/${insert[0]}" ];then
- while read olc
- do
- ((num++))
- tmp_olc=$(echo "$olc" | sed 's/ //g')
- tmp_olc=${tmp_olc%%=*}
- tmp_insert=$(echo "${insert[$n]}" | sed 's/ //g')
- tmp_insert=${tmp_insert%%=*}
- if [[ "$tmp_olc" == $tmp_insert && $n -le ${#insert[@]} ]];then
- ((n++))
- if [ $n -eq $[ ${#insert[@]} - 1 ] ];then
- echo "Insert: ${insert[$n]} @ ${insert[0]}[$num]"
- snum=$num
- nn=$n
- elif [ $n -eq ${#insert[@]} ];then
- echo -e "\033[33m${insert[$nn]} exits.\033[0m"
- exit 1
- fi
- else
- if [[ $num -eq $[ $snum + 2 ] && $nn -eq $n ]];then
- break
- fi
- fi
- done < $confpath/${insert[0]}
- if [ $nn -ne $[ ${#insert[@]} - 1 ] ];then
- echo -e "\033[31m Insert Error: None ${insert[$nn]} \033[0m $[ $nn + 1 ]"
- exit 1
- fi
- Str="${insert[$nn]}"
- sed -i "${snum}a\\$Str" $confpath/${insert[0]}
- else
- echo -e "\033[31m Insert Error:File not exist $confpath/${insert[0]} \033[0m"
- fi
- elif [ "X$1" == "Xdelete" ];then
- num=0
- n=1
- del=0
- OLD_IFS="$IFS"
- IFS="#"
- if [ "X$2" != "X" ];then
- delete=($2)
- else
- echo -e "\033[31m Delete Error \033[0m"
- exit 1
- fi
- IFS="$OLD_IFS"
- if [ -f "$confpath/${delete[0]}" ];then
- while read olc
- do
- ((num++))
- tmp_olc=$(echo "$olc" | sed 's/ //g')
- tmp_olc=${tmp_olc%%=*}
- tmp_delete=$(echo "${delete[$n]}" | sed 's/ //g')
- tmp_delete=${tmp_delete%%=*}
- #echo "$tmp_olc"
- if [[ $tmp_olc == $tmp_delete ]];then
- ((n++))
- if [ $n -eq $[ ${#delete[@]} ] ];then
- echo "Delete: ${delete[$n-1]} @ ${delete[0]}[$num]"
- del=1
- break
- fi
- fi
- done < $confpath/${delete[0]}
- if [ $n -ne $[ ${#delete[@]} ] ];then
- echo -e "\033[33mCan't find:\"${delete[$n]}\"@ $[ $n + 1 ] \033[0m"
- exit 1
- fi
- sed -i "${num}d" $confpath/${delete[0]}
- else
- echo -e "\033[31m Delete Error:File not exist $confpath/${delete[0]} \033[0m"
- fi
- elif [ "X$1" == "Xinsall" ];then
- OLD_IFS="$IFS"
- IFS="#"
- if [ "X$2" != "X" ];then
- insert=($2)
- else
- echo -e "\033[31m insall Error \033[0m"
- exit 1
- fi
- IFS="$OLD_IFS"
- if [ -f "$confpath/${insert[0]}" ];then
- sed -i "/${insert[1]}/a\\${insert[2]}" $confpath/${insert[0]}
- fi
- elif [ "X$1" == "Xcopy" ];then
- if [ "X$2" != "X" ];then
- OLD_IFS="$IFS"
- IFS="#"
- field=($2)
- IFS="$OLD_IFS"
- else
- echo -e "\033[31m Copy Error \033[0m"
- exit 1
- fi
- for((i=0;i<${#field[@]};i++)){
- Deep=$(dirname ${field[$i]} 2>/dev/null)
- copied_dir=$confpath/$Deep
- copied_file=$confpath/${field[$i]}
- bk_dir=$bkpath_whole/$Deep
- bk_file=$bkpath_whole/${field[$i]}
- if [ ! -d "$copied_dir" -o ! -f "$copied_file" ];then
- echo -e "\033[31m copy Error @ ${field[$i]}\033[0m"
- exit 1
- fi
- if [ -e "$bk_file" -a -s "$bk_file" ];then
- echo -e "\033[31m Error $bk_file exist and no empty. \033[0m"
- exit 1
- fi
- mkdir -p $bkpath_whole/$Deep && /bin/cp -f $copied_file $bk_file
- check=$(diff $bk_file $copied_file)
- if [ "$check" == "" ];then
- echo "copy $copied_file => $bk_file"
- else
- echo "error copy @ ${field[$i]}"
- fi
- }
- elif [ "X$1" == "Xrcopy" ];then
- if [ "X$2" != "X" ];then
- OLD_IFS="$IFS"
- IFS="#"
- field=($2)
- IFS="$OLD_IFS"
- else
- echo -e "\033[31m rcopy Error \033[0m"
- exit 1
- fi
- for((i=0;i<${#field[@]};i++)){
- if [ "${field[$i]}" == "" ];then
- continue
- fi
- Deep=$(dirname ${field[$i]} >/dev/null)
- rcopied_dir=$confpath/$Deep
- rcopied_file=$confpath/${field[$i]}
- bk_dir=$bkpath_whole/$Deep
- bk_file=$bkpath_whole/${field[$i]}
- if [ ! -d "$bk_dir" -o ! -f "$bk_file" ];then
- echo -e "\033[31m rcopy error $bk_dir not dir or $bk_file not file.\033[0m"
- exit 1
- fi
- if [ ! -s "$bk_file" ];then
- echo -e "\033[31m rcopy error $bk_file exist but empty. \033[0m"
- exit 1
- fi
- if [ ! -d "$rcopied_dir" ];then
- echo -e "\033[31m rcopy error:$rcopied_dir not dir. \033[0m"
- exit 1
- fi
- /bin/cp -f $rcopied_file $rcopied_file.$handle_date || ( echo -e "\033[31mrcopy: backup $rcopied_file failed.\033[0m" && exit 1)
- /bin/cp -f $bk_file $rcopied_file || ( echo -e "\033[31mrcopy: rcopy: restore $rcopied_file failed.\033[0m" && rm -rf $rcopied_file.$handle_date && exit 1)
- check=$(diff $bk_file $rcopied_file)
- if [ "$check" == "" ];then
- echo "restore $bk_file => $rcopied_file"
- rm -rf $rcopied_file.$handle_date
- else
- echo "error rcopy @ ${field[$i]}"
- /bin/cp -f $rcopied_file.$handle_date $rcopied_file
- rm -rf $rcopied_file.$handle_date
- fi
- }
- elif [ "X$1" == "Xversion" ];then
- echo "Version:1.0.7"
- else
- echo -e "批量備份還原給定目錄下的配置文件,可以備份某個文件中的一行或者多行、一個塊或者多個塊。恢復時,可以直接找到對應的行或者塊還原。"
- echo -e "插入字段時,可能精確到具體的某一行"
- echo -e "要被備份的文件格式有兩種:"
- echo -e "如:"
- echo -e "pattern_hot_switch=0 #行"
- echo -e "define server_proxy_host1{ #塊,塊以}作為結束符號"
- echo -e " part1=no1"
- echo -e " part2=no2"
- echo -e " part3=no3"
- echo -e "}"
- echo -e "Help:"
- echo -e "Backup Dir:"
- echo -e "\tServer Conf Dir: $confpath"
- echo -e "\tPartBKP Conf Dir: $bkpath"
- echo -e "\tWholeBKP Conf Dir: $bkpath_whole"
- echo "Usage: $0 [backup|restore|insert|delete|insall|copy|rcopy|version]"
- echo "backup:備份 restore:還原 insert:插入 delete:刪除 insall:批量插入 copy:拷貝文件 rcopy:還原拷貝的文件"
- echo -e "\tbackup 'server.config#+srcpattern#=request_src_type#...#+src src_acl#'"
- echo -e "\tbackup 'main.config#p_src_switch#url_log_switch#=url_log_switch#'"
- echo -e "\trestore"
- echo -e "\trestore main.config"
- echo -e "\tinsert 'server.config#def p_r t_default#...#r_ww_switch# xxx_xxx_xxx=1-2-3-'"
- echo -e "\tdelete 'server.config#def p_r t_default#...#r_ww_switch#xxx_xxx_xxx'"
- echo -e "\tinsall 'server.config#def p_r t_default#xxx_xxx_xxx=1-2-3-'"
- echo -e "\tcopy 'main.config#r.config#....'"
- echo -e "\trcopy 'main.config#r.config#....'"
- fi