重寫了伺服器備份的shell腳本,並加入了main函數

3 min

language: ja bn en es hi pt ru zh-cn zh-tw

大家好,我是無能。
我重寫了之前寫的用於創建備份的shell腳本。

簡介

我之前寫過這個腳本,但重新審視時,發現沒有包含刪除舊的備份tar.gz檔案的程式碼,而且感覺會變得有點長,所以我將它整理到一個main函數中。
對於我這個懶人來說,盡可能地縮短程式碼非常重要,所以我嘗試重寫了它。
實際上,如果能透過參數指定備份目的地和來源,會更具通用性,而且在cron中編寫時也會更清晰易懂,所以我遲早會這麼做。

分解

#!/bin/bash

MOUNT_DIR="/your/mount/point"

SRC_DIR="/want/to/backup/dir"
BK_DIR="backupdir"

EXCLUDE_FILE=""  # 指定排除檔案 --exclude=your/path
W_DIR=`echo $SRC_DIR | awk -F/ '{print $(NF)}'`

# 檢查掛載點,如果未掛載則掛載
check_mount() {
    df | grep "$MOUNT_DIR" > /dev/null
    if [ $? -ne 0 ]; then
        break
    else
        mount $MOUNT_DIR || exit 1
    fi
}

# 刪除舊的備份檔案
rm_old_backups() {
    BK_COUNT=`ls -1 $MOUNT_DIR/$BK_DIR/*.tar.gz 2>/dev/null | wc -l`
    if [ "$BK_COUNT" -ge 3 ]; then
        ls -1t $MOUNT_DIR/$BK_DIR/*.tar.gz | tail -n +4 | while read file; do
            rm -f "$file"
        done
    fi
}

# 創建備份
create_backup() {
    rsync -av $EXCLUDE_FILE $SRC_DIR $MOUNT_DIR/$BK_DIR
    tar cfz $MOUNT_DIR/$BK_DIR/"$W_DIR"_`date +"%Y%m%d"`.tar.gz -C $MOUNT_DIR/$BK_DIR $W_DIR
    rm -rf $MOUNT_DIR/$BK_DIR/$W_DIR/*
}

main() {
    check_mount  # 檢查掛載,如果需要則掛載
    mkdir -p $MOUNT_DIR/$BK_DIR  # 創建備份目錄
    rm_old_backups  # 刪除舊的備份
    create_backup  # 創建新的備份
    umount $MOUNT_DIR || exit 1  # 解除掛載
}

main

由於我預期會進行掛載/解除掛載操作,因此需要加入相關判斷。奇怪的是,當我嘗試使用mountpoint指令來判斷是否已掛載時,即使已經掛載,有時也會顯示「未掛載」,導致無法取得正確的回傳值。
因此,我突然想到,如果沒有掛載,它就不會出現在df的結果中。所以,透過grep df的標準輸出,並根據是否能grep到掛載點的回傳值來判斷,應該是相當可靠的。

原本我是用cp指令簡單地複製一次,然後再用tar打包,但因為我想指定「複製時排除的檔案」,聽說rsync可以用。這就是為什麼大家都在用rsync的原因吧。

之所以特意指定$W_DIR,是因為rsync會用到,所以需要先建立這個值。
而關鍵在於判斷並刪除舊的tar.gz檔案。透過ls來確認,就不會像find那樣貪婪地深入下層目錄,因此我認為這樣對磁碟I/O的負擔較小,也更安全,所以就這麼做了。
這樣一來,透過tail取得檔案名稱,就能明確決定允許保留多少個檔案,這不是挺好的嗎?

結尾

老實說,我感覺其實沒必要特地寫成main函數,但結果看起來確實更清晰了,所以就這樣吧。
那麼,下次再見了。

Related Posts