開発現場で最も重要度の高いシェルスクリプトは、やはりバックアップ関連でしょう。作成中の環境設定やスクリプトなど、デグレや紛失から守るために、定期的に他のディスクへ退避することが求められます。
対象ファイルが1つや2つ程度なら手動で退避することも考えられますが、他のエンジニアとの共同作業の場合、定義ファイルや設定ファイル、実行スクリプトなど‥所定のディレクトリを定期的にバックアップすることをお勧めします。手動作業ではとても追いつきません。
この記事では、外部ファイルにて指定されたファイルを圧縮して退避するスクリプトを作成します。実行スケジュールはクーロンを想定しています。
実行スクリプト環境の準備
バックアップを行うスクリプトは、これまで作成してきたロジックを組み合わせて作成していきます。
簡単な仕様
- 想定するバックアップ対象
- ディレクトリ(サブディレクトリ含む)
- ファイル(ワイルドカード指定可)
- 対象の指定・除外選択を可能とする
- 対象指定外部ファイル名:backupFiles.target
- 除外指定外部ファイル名:buckupFiles.ignore
- エラーハンドリング
- バックアップの失敗を検知するため、エラーはシスログへ出力する
- メッセージ出力
- 外部ファイルより取得し所定のログファイルへ出力する。
前提
Beエンジニアでシェルスクリプトを実行する環境は下記の通りとします。
実行環境
BASE_DIR(任意のディレクトリ)
- scripts
- bin(実行スクリプト格納領域)
- func.sh (実行ファイル)
- com(共通スクリプト格納領域)
- comFunc.shrc(共通関数定義ファイル)
- etc(設定ファイル等の格納領域)
- message.conf(メッセージ定義ファイル)
- log(スクリプト実行ログの格納領域)
- スクリプト名.log
- tmp(テンポラリ領域)
- rep(レポート出力領域)
- bin(実行スクリプト格納領域)
バックアップ対象ファイルの準備
バックアップの実行環境として「/root/」直下へ「test」ディレクトリを想定しています。
上記ディレクトリ構成のうち、赤枠内をバックアップ対象とし、定期的にファイルを指定ディレクトリへ退避します。なお、退避する必要のないファイルは別途、除外設定ファイルへ除外対象を記入することにより、バックアップの対象から除外するものとします。
外部ファイルの作成
取得対象となるファイル・ディレクトリ及び、除外対象となるファイル・ディレクトリを指定します。今回はバックアップの対象から一部の「ファイル」や「ディレクトリ」を除外して対象をバックアップします。また、対象がファイルの場合はそのまま、ディレクトリの場合は「tar.gz」形式にアーカイブして指定格納領域へ格納します。
[ <BASE_DIR>/scripts/etc/backupFiles.target.list ]
取得対象ファイルorディレクトリ
/root/test1
/root/test/test2/test2-1
/root/test/test2/test2-3/test2-3.txt
[ <BASE_DIR>/scripts/etc/backupFiles.ignore.list ]
除外対象ファイルorディレクトリ
test1-1*
メッセージ定義ファイルの作成
出力するメッセージは外部ファイルからメッセージIDを元に取得するものとします。
I-00000番台:INFOMATION(情報)※ 今回は未使用
W-00000番台:WARNING(警告)
E-00000番台:ERROR(エラー)
[ <BASE_DIR>/scripts/etc/message.conf ]
message.conf
# Warning messages
W-00001 user.warn "The number of arguments is incorrect."
W-00002 user.warn "The target file or target directory cannot be found."
W-00003 user.warn "There is an error in the option specification."
W-00004 user.warn "The target does not exist. Skip"
# Error messages
E-00001 user.err "Lock failed due to multiple startup."
E-00002 user.err "Failed to unlock."
E-00003 user.err "Failed to copy the file."
実行シェルの作成
ワイルドカード指定の場合は、指定ファイルを検索してコピーを行います。
多重起動禁止処理
多重起動禁止処理を設定します。詳細については下記リンクページを参照ください。
ファイルバックアップ処理
ファイルのバックアップロジックを実装します。バックアップは下記の観点3つを考慮し実装します。
ポイント
- 取得対象の指定にワールドカードが指定された場合
- 取得対象がファイルの場合
- 取得対象がディレクトリの場合
本スクリプトのログ出力は「スクリプト名+.log」ファイルへ出力します。
監視設定の観点からシスログへの出力を組み込む場合、下記のリンクを参照ください。
ワイルドカード指定の処理
取得対象ファイルに「/取得対象ファイル*」の様に「*(ワイルドカード)」が指定された場合の処理を行います。
1 2 3 4 5 6 7 8 |
# Check param(wildcards) if echo ${src} | egrep -q -e '[*]'; then find `dirname ${src}` -name ${src##*/} | xargs -i cp -rp {} ${dst} if [ $? -ne ${JOB_OK} ]; then logOut "$(eval echo $(getMsg E-00003))" "src:[ ${src} ] dst:[ ${dst} ]" fi continue fi |
※ ワイルドカードで指定されたファイルは、原形のまま(アーカイブ化せず)そのまま引数で指定された格納先ディレクトリへ格納します。
ファイル・ディレクトリのバックアップロジック
取得対象がファイルの場合、原形のまま(アーカイブせず)そのまま引数で指定された格納先ディレクトリへ格納します。取得対象がディレクトリの場合、対象ディレクトリを圧縮(アーカイブ化)して、引数で指定された格納ディレクトリへ格納します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# cp the object. if [ -f "$src" ]; then dst_file="${dst}/${src##*/}" /bin/cp -pf ${src} ${dst_file} if [ $? -ne ${JOB_OK} ]; then logOut "$(eval echo $(getMsg W-00004))" "src:[ ${src} ] dst_file:[ ${dst_file} ]" continue fi else dst_file=${dst}/`echo ${src#*/} | sed "s/\//\_/g"`.tar.gz /bin/tar -zcf ${dst_file%*_} ${src} --exclude-from=$ignore_list if [ $? -ne ${JOB_OK} ]; then logOut "$(eval echo $(getMsg W-00004))" "src:[ ${src} ] dst_file:[ ${dst_file} ]" continue fi fi |
※ 取得対象がディレクトリの場合、パスに含まれる「/(スラッシュ)」を「_(アンダースコア)」へ変更しアーカイブ名としています。
実行スクリプト
バックアップ処理を実行ファイルへ組み込みます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
#!/bin/sh #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # # ver.1.0.0 yyyy.mm.dd # # Usage: # # sh /root/scripts/bin/backupFiles.sh -d [ 格納先 ] # # Description: # 外部ファイルにて指定されたファイルおよびディレクトリを # 引数で指定されたディレクトリへバックアップする。 # # 設計書 # なし # #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ # <変更履歴> # Ver. 変更管理No. 日付 更新者 変更内容 # 1.0 xxx-xxxx xxxx/xx/xx 〇〇〇〇 新規作成 #_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/i # 共通関数定義ファイル読み込み . `dirname $0`/../com/comFunc.shrc # ---------------------------------------------------------- # variables (変数の宣言領域) # ---------------------------------------------------------- scope="var" # 変数定義 os=`uname -s` hostname=`hostname -s` roop="ループ" head="ファイルバックアップ機能" user=`whoami` src= dst= target_list="${ETC_PATH}/backupFiles.target.list" ignore_list="${ETC_PATH}/backupFiles.ignore.list" # ---------------------------------------------------------- # functions (関数を記述する領域) # ---------------------------------------------------------- scope="func" # --------------------------------------------------- # 終了処理関数 # --------------------------------------------------- endFunc() { rc=${1} msg_id=${2} add_msg=${3} rmLockDir # Judgment of exit code if [ ${rc} == ${JOB_OK} ] ;then logOut ${msg_id} "${head}" else logOut ${msg_id} "${head} ${add_msg}" fi exitLog ${rc} } # ---------------------------------------------------------- # 使用法表示 # ---------------------------------------------------------- # return N/A # ---------------------------------------------------------- usage() { cat <<EOUSAGE ----------------------------------------------------------------- Usage: $0 [< options >] Options: -d destination : Specify the storage destination ------------------------------------------------------------------ EOUSAGE } # ---------------------------------------------------------- # 引数チェック # ---------------------------------------------------------- # param 1 param # return N/A # ---------------------------------------------------------- checkArg() { if [ $# -lt 1 ]; then endFunc ${JOB_WR} "$(eval echo $(getMsg W-00001))" "${@}" fi } # ---------------------------------------------------------- # パラメータチェック # ---------------------------------------------------------- # param 1 file or directory # return exist:0 not exist:1 # ---------------------------------------------------------- checkParam() { # Check file or directory. if [ ! -e "$1" ]; then return 1 fi return 0 } # ---------------------------------------------------------- # ターゲットファイル及び除外ファイルの存在確認 # ---------------------------------------------------------- # param 1 Configuration file # return N/A # ---------------------------------------------------------- checkConf() { if [ ! -f $target_list ]; then endFunc ${JOB_WR} "$(eval echo $(getMsg W-00002))" "conf:${target_list}" fi if [ ! -f $ignore_list ]; then endFunc ${JOB_WR} "$(eval echo $(getMsg W-00002))" "conf:${ignore_list}" fi } # ---------------------------------------------------------- # 格納先ディレクトリ作成 # ---------------------------------------------------------- # return N/A # ---------------------------------------------------------- prepareDirs() { for d in "${dst}"; do if [ ! -d ${d} ]; then /bin/mkdir -p ${d} fi done } # ---------------------------------------------------------- # pre-process (事前処理ロジックを記述する領域) # ---------------------------------------------------------- scope="pre" # Log function start startLog # Get the value from the argument. while getopts d: opts; do case $opts in d) dst=$OPTARG ;; *) usage endFunc ${JOB_ER} "$(eval echo $(getMsg W-00003))" esac done; # Set trap control. trap "endFunc" 1 2 3 15 # Argument check checkArg ${@} # Existence check of setting file. checkConf # Multiple startup prohibition processing if mkLockDir; then logOut Successfully locked. else abort Could not acquire lock. fi # ---------------------------------------------------------- # main-process (メインロジックを記述する領域) # ---------------------------------------------------------- scope="main" # directory preparation. prepareDirs ${dst} # Loop processing of target worth. sed '/^#/d;/^$/d' ${target_list} | while read src ; do logOut "${roop}Start! target:[ ${src} ]" # Check param(wildcards) if echo ${src} | egrep -q -e '[*]'; then find `dirname ${src}` -name ${src##*/} | xargs -i cp -rp {} ${dst} if [ $? -ne ${JOB_OK} ]; then logOut "$(eval echo $(getMsg E-00003))" "src:[ ${src} ] dst:[ ${dst} ]" fi continue fi # Checking the validity of the parameter. if ! checkParam $src; then logOut "$(eval echo $(getMsg W-00004))" "target:[ ${src} ]" continue fi # cp the object. if [ -f "$src" ]; then dst_file="${dst}/${src##*/}" /bin/cp -pf ${src} ${dst_file} if [ $? -ne ${JOB_OK} ]; then logOut "$(eval echo $(getMsg W-00004))" "src:[ ${src} ] dst_file:[ ${dst_file} ]" continue fi else dst_file=${dst}/`echo ${src#*/} | sed "s/\//\_/g"`.tar.gz /bin/tar -zcf ${dst_file%*_} ${src} --exclude-from=$ignore_list if [ $? -ne ${JOB_OK} ]; then logOut "$(eval echo $(getMsg W-00004))" "src:[ ${src} ] dst_file:[ ${dst_file} ]" continue fi fi logOut "${roop}Ended! target [${src}]" done # ---------------------------------------------------------- # post-process (事後処理ロジックを記述する領域) # ---------------------------------------------------------- scope="post" # 終了関数コール endFunc ${rc} |
本スクリプトでは、取得対象となるファイル or ディレクトリが存在しない場合、警告ログを出力し処理をスキップします。(停止はしません)
実行結果
作成したスクリプトを実行します。
[ 実行結果 ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
[root@jb1 bin]# sh backupFiles.sh -d /root/backupDir [root@jb1 ~]# ls -l total 12 drwxr-xr-x 2 root root 4096 Mar 18 10:24 backupDir #👈 バックアップディレクトリ drwxr-xr-x 7 root root 4096 Mar 13 10:34 scripts drwxr-xr-x 4 root root 4096 Mar 16 09:07 test [root@jb1 ~]# tree --charset=C backupDir backupDir |-- root_test_test1.tar.gz #👈 アーカイブ化 |-- root_test_test2_test2-1.tar.gz #👈 アーカイブ化 `-- test2-3.txt #👈 原型のまま退避 0 directories, 3 files [root@jb1 ~]# cd backupDir/ [root@jb1 backupDir]# tar -xzf root_test_test1.tar.gz #👈 アーカイブを展開 [root@jb1 backupDir]# tree --charset=C root #👈 除外対象は含まれていない root `-- test `-- test1 |-- test1-2 | `-- test1-2.txt `-- test1-3 `-- test1-3.txt 4 directories, 2 files |
バックアップスクリプトを実行した結果、一部のファイルやディレクトリを除外してバックアップ対象が取得されています。
※ 本スクリプト利用により発生した利用者の損害全てに対し、いかなる責任をも負わないものとし、損害賠償をする一切の義務はないものとします。