
我有一個rsync
進程將來源儲存庫(受版本控制)的內容同步到共用 NFS 掛載中。
這種情況(儘管很糟糕)是目標資料夾包含比來源資料夾更多的內容,因為其他內容從不同的來源同步到目標資料夾。例如,資料夾結構可能如下所示:
來源
a/a1.txt
a/a2.txt
b/b1.txt
目的地
a/a1.txt
a/a2.txt
a/a3.txt
b/b1.txt
c/c1.txt
(在此範例中,a/a3.txt
和c/c1.txt
從其他地方同步到目的地。實際上,這涉及多個其他來源,並且這些來源的內容/流程不會受到影響。)
現在假設來源資料夾刪除了該a/a2.txt
檔案。使用現有設置,該檔案不會在目標位置被刪除;但使用--delete
會導致其他文件被刪除,並且要求不要這樣做。
如何--delete
在這個rsync上使用而又滿足要求?由於來源目錄是受版本控制的,因此很容易獲得該目錄的前後情況,因此可以使用原始來源目錄作為參考來計算差異備份,但這是最好的方法嗎?
答案1
你不能rsync --delete
這樣使用。它是無狀態的,並且不記錄運行期間刪除了哪些檔案。該--delete
標誌只是指示rsync
刪除目標上不存在於來源上的每個檔案。
為了實現這種受限刪除,我認為您需要維護自己的狀態。既不rsync
也unison
不能為你做這件事。
以下不是完整的錯誤安全解決方案;這是一個起點。 (但是,它確實處理具有奇怪名稱的檔案 - 包括那些包含嵌入換行符的檔案。)
假設有兩個目錄src
和dst
。 (就本範例而言,本地或遠端並不重要dst
。)
# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z > .state.src
每次我們執行備份時,請執行以下程式碼
# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/
# Determine the set of files to delete in "dst/"
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z | tee .state.src.new |
LC_ALL=C comm -z - -13 .state.src |
ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'
# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src
如果您的版本comm
(例如我的版本)早於 GNU coreutils 8.25 並且沒有該-z
標誌,您可以使用以下替代解決方法:
# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort > .state.src
每次我們執行備份時,請執行以下程式碼
# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/
# Determine the set of files to delete in "dst/"
( cd src && find . -type f -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort | tee .state.src.new |
LC_ALL=C comm -13 - .state.src |
tr '\0\n' '\n\0' |
ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'
# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src