centos使用lftp備份檔案

2022-11-09 18:00:29

一直以來專案的檔案沒有備份,最近需要增加備份,本來以為備份是IT的工作,結果IT說工作忙,拖了半個月給分配完ftp伺服器後說不給備份,需要我們開發自己備份。。。我特麼***

對於ftp備份,咱是沒有經驗的,IT給提示了一個工具:lftp。

關於lftp的介紹可以看這篇文章:https://blog.csdn.net/weixin_43135696/article/details/121541807,其中lftp -c命令我沒搞懂到底要怎麼執行,-c後面的cmd命令總提示不存在。

而備份檔案主要用的是lftp mirror命令,參考:https://blog.51cto.com/riverxyz/1869476,總結如下:

mirror [OPTS] [source [target]]
[opts]引數如下:
-c, --continue 續傳上次的任務 -e, --delete 刪除遠端目錄上不存在的檔案(刪的是本地啊注意)    --delete-first 在傳輸新檔案之前刪除舊的檔案    --depth-first 進入下一層目錄優先於檔案傳輸 -s, --allow-suid 根據遠端站點設定suid/sgid位元位    --allow-chown 嘗試將自己設定為檔案所有者和所有組    --ascii 使用ascii方式傳輸(隱含了--ignore-size)    --ignore-time 決定是否下載時忽略時間因素    --ignore-size 決定是否下載時忽略檔案大小因素    --only-missing 只下載缺少的檔案    --only-existing 只下載已經存在於目標資料夾中的檔案 -n, --only-newer 只下載新檔案(-c引數無法運作)    --no-empty-dirs 不建立空資料夾(隱含了--depth-first) -r, --no-recursion 不進入子資料夾    --no-symlinks 不建立符號連結 -p, --no-perms 不設定檔案許可權    --no-umask 不使用檔案預設許可權 -R, --reverse 反向映象(上傳檔案,注意大寫) -L, --dereference 將符號連結作為 檔案下載 -N, --newer-than=SPEC 只下載比指定時間晚的檔案    --on-change=CMD 只要有檔案或資料夾存在差異就執行命令CMD    --older-than=SPEC 只下載比指定時間早的檔案    --size-range=RANGE 只下載大小在指定區間上的檔案 -P, --parallel[=N] 並行下載N個檔案    --use-pget[-n=N] 使用pget傳輸每個檔案    --loop 迴圈直到找不到差異 -i RX, --include RX 包括相匹配的檔案 -x RX, --exclude RX 不包括相匹配的檔案 -I GP, --include-glob GP 包括相匹配的檔案 -X GP, --exclude-glob GP 不包括相匹配的檔案 -v, --verbose[=level] 輸出等級,加該引數輸出執行詳情,不加則在底部變動顯示。    --log=FILE 將執行的lftp命令寫入檔案FILE    --script=FILE 將lftp命令寫入檔案FILE,但不執行    --just-print, --dry-run 與--script=-相同    --use-cache 使用快取目錄列表

我的想法是每天定時將本地資料夾備份到遠端ftp伺服器上,所以執行

lftp -e "mirror --reverse --only-missing --only-newer 本地資料夾 ftp資料夾 --parallel=5 --log=紀錄檔.log" 賬號:密碼@ftp伺服器ip
或
lftp -u 賬號,密碼 -e "mirror --reverse --only-missing --only-newer --verbose 本地資料夾 ftp資料夾 --parallel=3 --log=紀錄檔.log" ftp伺服器ip

以上兩個方式效果是一樣的。其中引數 --verbose可以在控制檯輸出執行詳情,不想輸出的可以不加,執行完成最終會顯示本次執行上傳了多少檔案和建立了多少資料夾。

現實遠非單個資料夾,由於早期設計原因,各個模組的資料夾是存在不同的目錄下的,而且命名方式「各顯神通」,有的以模組為根目錄,有的以年月為根目錄,有的模組只有根目錄一級目錄(所有的檔案都在一級目錄下),有的模組次級目錄是年月而有的次級目錄是年月日...

針對已經存在的目錄儘量不進行大的變動了,但對於檔案量大的模組還是不得不進行改造,比如上面說的只有模組一級目錄的資料夾如果每日增量檔案不小則需要新增年月(甚至年月日)次級目錄。歷史的目錄只需按上面的命令執行全量備份即可,對於每日的增量檔案進行定時任務的增量備份。

按以上幾種情況整合bat指令碼如下:

#!/bin/bash
# 每小時執行一次同步檔案到ftp伺服器,要考慮跨天情況

# 設定今天對應的年月(yyyy-mm)、日期(dd)、時間(yyyy-mm-dd HH:MM:SS,注意中間空格的方式)
date_ym=`date +%Y-%m`
date_d=`date +%d`
date_ymd=`date +%Y-%m-%d" "%H:%M:%S`

# 半年前日期
halfyear_ymd=`date -d "-179 day" +%Y-%m-%d`
# 半年前對應日期再往前一小時所屬日期,只能按小時數(24*179+1)
halfyear_last_hour_ymd=`date -d "-4297 hour" +%Y-%m-%d`

# 當前時間往前一小時所屬年月日
last_hour_ymd=`date -d "-1 hour" +%Y-%m-%d`
last_hour_ym=`date -d "-1 hour" +%Y-%m`
last_hour_d=`date -d "-1 hour" +%d`
last_hour_h=`date -d "-1 hour" +%H`

echo $date_ymd"開始同步------------------"
echo $last_hour_d
echo $last_hour_ym
echo $last_hour_ymd
echo $last_hour_h
echo $halfyear_ymd
echo $halfyear_last_hour_ymd

# 將執行紀錄檔儲存進指令碼目錄下屬紀錄檔資料夾/年月日資料夾,先建立資料夾,否則報錯不存在目錄
mkdir -p /本地指令碼目錄/logs/$last_hour_ym/$last_hour_d/

# 同步一小時前所在月份資料夾,比如資料夾2022-10
if [ -d "/本地目錄/"$last_hour_ym ]; then
    echo $last_hour_ym
lftp -u 賬號,密碼 ftp伺服器ip << EOF
    mirror --reverse --only-missing --only-newer /本地目錄/$last_hour_ym ftp伺服器目錄/$last_hour_ym --parallel=3 --log=/本地指令碼目錄/logs/$last_hour_ym/$last_hour_d/$last_hour_d-$last_hour_h.log
    bye
EOF
else
    echo $last_hour_ym"不存在"
fi



# 同步具體分類資料夾,不帶年月子資料夾
for item in 模組1目錄 模組2目錄 模組N目錄
do
    echo $item;
lftp -u 賬號,密碼 ftp伺服器ip << EOF
    mirror --reverse --only-missing --only-newer /本地目錄/$item ftp伺服器目錄/$item --parallel=3 --log=/本地指令碼目錄/logs/$last_hour_ym/$last_hour_d/$item-$last_hour_h.log
    bye
EOF

done



# 同步具體分類資料夾,帶年月(模組名/2022-10)子資料夾
for item in 模組11目錄 模組22目錄 模組NN目錄
do
    if [ -d "/本地目錄/"$item"/"$last_hour_ym ]; then
        echo $item;
lftp -u 賬號,密碼 ftp伺服器ip << EOF
    mirror --reverse --only-missing --only-newer /本地目錄/$item/$last_hour_ym ftp伺服器目錄/$item/$last_hour_ym --parallel=3 --log=/本地指令碼目錄/logs/$last_hour_ym/$last_hour_d/$item-$last_hour_h.log
    bye
EOF
    else
        echo $item"/"$last_hour_ym"不存在"
    fi
done



# 同步具體分類資料夾,帶年月日(模組名/2022-10-29)子資料夾的
for item in 模組111目錄 模組222目錄 模組NNN目錄
do
    if [ -d "/本地目錄/"$item"/"$last_hour_ymd ]; then
        echo $item;
lftp -u 賬號,密碼 ftp伺服器ip << EOF
    mirror --reverse --only-missing --only-newer /本地目錄/$item/$last_hour_ymd ftp伺服器目錄/$item/$last_hour_ymd --parallel=3 --log=/本地指令碼目錄/logs/$last_hour_ym/$last_hour_d/$item-$last_hour_h.log
    bye
EOF
    else
        echo $item"/"$last_hour_ymd"不存在"
    fi

done


echo '同步結束----------------------'
定時執行備份的指令碼

以上指令碼涉及諸多知識,對於不熟悉linux(shell、bat)命令的人來說會踩很多坑,下面備註下:

1、如何寫一個linux指令碼,可參考:https://blog.csdn.net/scdncby/article/details/112339627,其中首要備註#!/bin/bash,很多時候沒有這個宣告會報錯。

2、定時備份那麼就要涉及到日期或者時間值,尤其是對於0點跨天時,凌晨23點以後新上傳的檔案,在第二天凌晨0點後如果只是按日期備份,那麼23點的檔案就容易漏掉,所以要按當前時間的前一小時所屬的日期執行判斷。這裡就需要用到linux的日期取值函數。第一個搜到的參考文章是:https://blog.51cto.com/sadlar/1332921,然後自己摸索,到拼接年月日+時間的時候遇到一點障礙,不過還是解決了~~,關於linux字串拼接可以參考文章:https://blog.csdn.net/sodalife/article/details/110673401。最終得出以下取值:

# 設定今天對應的年月(yyyy-mm)、日期(dd)、時間(yyyy-mm-dd HH:MM:SS,注意中間空格的方式)
date_ym=`date +%Y-%m`
date_d=`date +%d`
date_ymd=`date +%Y-%m-%d" "%H:%M:%S`

# 半年前日期
halfyear_ymd=`date -d "-179 day" +%Y-%m-%d`
# 半年前對應日期再往前一小時所屬日期,只能按小時數(24*179+1)
halfyear_last_hour_ymd=`date -d "-4297 hour" +%Y-%m-%d`

# 當前時間往前一小時所屬年月日
last_hour_ymd=`date -d "-1 hour" +%Y-%m-%d`
last_hour_ym=`date -d "-1 hour" +%Y-%m`
last_hour_d=`date -d "-1 hour" +%d`
last_hour_h=`date -d "-1 hour" +%H`

3、判斷資料夾是否存在。linux中判斷用的也是if語句,但是又有不同,比如在centos中判斷條件是用中括號括起來的,而且必須與if關鍵字之間和條件之間有空格(if [ 條件 ]; ),我之前就吃過這個空格的虧。。可以參考文章:https://blog.csdn.net/hhd1988/article/details/113552656 和https://blog.csdn.net/qq_45484237/article/details/124023066。 判斷資料夾目錄用的是-d指令,然後目錄地址可以是拼接起來的,甚至是拼接變數名,這就很強大。比如:

last_hour_ym=`date -d "-1 hour" +%Y-%m`
if [ -d "/本地目錄/"$last_hour_ym ]; then
    echo $last_hour_ym
else
    echo $last_hour_ym"不存在"
fi

4、關於for迴圈,可以參考文章:https://www.cnblogs.com/shigongp/p/16686336.html,for迴圈既可以迴圈資料夾目錄,也可以迴圈羅列的字串(多個字串直接用空格隔開),本文用的是字串羅列的,更多場景應該是迴圈資料夾目錄吧。

5、關於命令塊<<,有些時候,linux命令會進入新的控制端,比如ssh,ftp等,進入新控制端執行需要的命令,這時有兩種方式,一種是直接將所有的命令用&拼接起來,一種就是使用命令塊符號<<。關於具體使用本文不做詳解,直接舉例,以最上面lftp的命令為例,執行命令

lftp -e "mirror --reverse --only-missing --only-newer 本地資料夾 ftp資料夾 --parallel=5 --log=紀錄檔.log" 賬號:密碼@ftp伺服器ip

後會進入lftp控制端,後面的所有命令都是在lftp控制端裡,只有手動執行bye命令才會退出回到主伺服器控制端。但在指令碼裡直接寫兩行命令肯定是不行的,需要用寫在命令塊裡,寫作:

lftp -u 賬號,密碼 ftp伺服器ip << EOF
    mirror --reverse --only-missing --only-newer /本地目錄/$last_hour_ym ftp伺服器目錄/$last_hour_ym --parallel=3 --log=/本地指令碼目錄/logs/$last_hour_ym/$last_hour_d/$last_hour_d-$last_hour_h.log
    bye
EOF

命令解讀為:先登入ftp伺服器,然後執行備份操作,然後bye退出。這裡有個要注意的點,EOF塊所屬的程式碼必須頂格寫,不然會報錯:warning: here-document at line 5 delimited by end-of-file (wanted `EOF`,可以參考文章:https://blog.csdn.net/weixin_42575593/article/details/83686244


設計完了指令碼,就考慮怎麼設為定時任務了。

centos中設定定時任務用的是crontabs,可以參考文章:https://blog.csdn.net/m0_48096446/article/details/122378767 ,查了下我的伺服器已經安裝了,所以直接修改/etc/crontab設定(50 0,9-22 * * * root /bak/bak_files.sh)執行時間,後來發現執行crontab /etc/crontab後覆蓋了原有的定時任務,問了IT說原來的是物理機和伺服器之間同步時間的,md,還得讓他們搞回來。。。

至此,定時備份設定完成。