Smart backup and restoration of configuration files
Use Cases:
Every time we upgrade or update services for many machines, we need to back up one or more rows in the configuration file, or one or more data blocks, after upgrading and updating services, you can re-write the corresponding backup data back to the new configuration file. operations on a large number of servers will waste a lot of time and effort, the following script is used to accomplish similar tasks.
Main functions:
1. Backup a specified row or multiple rows, one block or multiple blocks
2. Back up a specified file
3. Restore all partial backups and all backups
4. Insert a regular expression matching in the configuration file]
5. precisely locate and delete the configuration file
6. Insert configuration files in batches after similar rows
Service configuration file example:
- Server. config:
- #### Configuration file example:
- Ser_max_connection = 6000 # Row
- Ser_min_connection = 10
- Ser_time_out = 60
- Ser_time_spent = 120
- Server tcp_nodes {# Block
- Ser_client_ip = ipv4
- Ser_client_len = 20 * N
- Ser_client_syn = yes
- Ser_client_ack = yes
- }
The following is the code implementation of the shell script. The script mainly uses the sed tool to complete the configuration editing function. This script is changed to a general version based on the actual application environment, and has not been strictly tested. If you want to use this script, perform a serious test based on your environment. If you have a better idea, please join the QQ group: 63565867.
- #! /Bin/bash
- # DianDian
- Proconf =/usr/local/server/etc # main directory to be backed up. The file name passed in the parameter and the path will be merged.
- Confpath = $ proconf
- Bkpath =/usr/local/src/bkconfig/part # directory for saving part of the backup file
- Bkpath_whole =/usr/local/src/bkconfig/whole # back up the directory of the entire file
- Handle_date = $ (date "+ % y % m % d % H % M ")
- Mkdir-p $ bkpath $ bkpath_whole
- FJ = '^ \ +'
- FD = '^ \ ='
- ALLFILE = ""
- Function multidir () {# dirname # A Recursive function in shell is used to obtain all files in a directory. [if the file name contains spaces, errors may occur]
- 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 [31 m Error \ 033 [0 m"
- 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 [31 m Error $ B _CONF exist and no empty. \ 033 [0 m"
- 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 [31 m Error: Skip $ {field [0]} \ 033 [0 m"
- Fi
- Elif ["X $1" = "Xrestore"]; then
- If ["X $2 "! = "X"]; then
- List = ('LS-f $ bkpath/$2>/dev/null ')
- Else
- # List = ('LS-d $ bkpath/* 2>/dev/null ')
- Multidir $ bkpath
- List = ($ ALLFILE)
- Fi
- If ["$ List" = ""]; then
- Echo-e "\ 033 [31 m restore: no valid file. \ 033 [0 m"
- Fi
- For I in $ {List [*]}
- Do
- Num = 0
- B _CONF = "$ I"
- Base = $ (basename $ I)
- If ["$ base" = ""-a-s $ B _CONF]; then
- Echo-e "\ 033 [31 m restore error @ $ B _CONF \ 033 [0 m"
- 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 [31 m restore error @ $ F_CONF \ 033 [0 m"
- 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 1 p)
- 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 [33 mError: $ Err \ 033 [0 m"
- 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 [31 m Insert Error \ 033 [0 m"
- 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 [33 m $ {insert [$ nn]} exits. \ 033 [0 m"
- 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 [31 m Insert Error: None $ {insert [$ nn]} \ 033 [0 m $ [$ nn + 1]"
- Exit 1
- Fi
- Str = "$ {insert [$ nn]}"
- Sed-I "$ {snum} a \ $ Str" $ confpath/$ {insert [0]}
- Else
- Echo-e "\ 033 [31 m Insert Error: File not exist $ confpath/$ {insert [0]} \ 033 [0 m"
- 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 [31 m Delete Error \ 033 [0 m"
- 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 [0 m"
- Exit 1
- Fi
- Sed-I "$ {num} d" $ confpath/$ {delete [0]}
- Else
- Echo-e "\ 033 [31 m Delete Error: File not exist $ confpath/$ {delete [0]} \ 033 [0 m"
- Fi
- Elif ["X $1" = "Xinsall"]; then
- OLD_IFS = "$ IFS"
- IFS = "#"
- If ["X $2 "! = "X"]; then
- Insert = ($2)
- Else
- Echo-e "\ 033 [31 m insall Error \ 033 [0 m"
- 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 [31 m Copy Error \ 033 [0 m"
- Exit 1
- Fi
- For (I = 0; I <$ {# field [@]}; I ++ )){
- Deep =2 (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 [31 m copy Error @ $ {field [$ I]} \ 033 [0 m"
- Exit 1
- Fi
- If [-e "$ bk_file"-a-s "$ bk_file"]; then
- Echo-e "\ 033 [31 m Error $ bk_file exist and no empty. \ 033 [0 m"
- 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 [31 m rcopy Error \ 033 [0 m"
- 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 [31 m rcopy error $ bk_dir not dir or $ bk_file not file. \ 033 [0 m"
- Exit 1
- Fi
- If [! -S "$ bk_file"]; then
- Echo-e "\ 033 [31 m rcopy error $ bk_file exist but empty. \ 033 [0 m"
- Exit 1
- Fi
- If [! -D "$ rcopied_dir"]; then
- Echo-e "\ 033 [31 m rcopy error: $ rcopied_dir not dir. \ 033 [0 m"
- Exit 1
- Fi
- /Bin/cp-f $ rcopied_file. $ handle_date | (echo-e "\ 033 [31 mrcopy: backup $ rcopied_file failed. \ 033 [0 m "& exit 1)
- /Bin/cp-f $ bk_file $ rcopied_file | (echo-e "\ 033 [31 mrcopy: rcopy: restore $ rcopied_file failed. \ 033 [0 m "& 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 "batch backup restores the configuration files under a given directory. You can back up one or more lines, one block, or multiple blocks in a file. During restoration, you can directly find the corresponding row or block restoration. "
- Echo-e "when inserting a field, it may be accurate to a specific line"
- Echo-e "there are two file formats to be backed up :"
- Echo-e "For example :"
- Echo-e "pattern_hot_switch = 0 # Row"
- Echo-e "define server_proxy_host1 {# block, block with} as the end symbol"
- 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: backup restore: restore insert: insert delete: delete insall: Batch insert copy: copy file rcopy: restore copied file"
- 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