使用 Rsync 檢測目錄移動
我目前用於將一個 HDD 備份到另一個(本地,而不是遠端)的命令是
rsync --info=PROGRESS2,BACKUP,DEL -ab --human-readable --inplace --delete-after --debug=NONE --log-file=/media/blueray/WDPurple/rsync.log --backup-dir=red_rsync_bak.$(date +"%d-%m-%y_%I-%M-%S%P") --log-file-format='%t %f %o %M' --exclude='lost+found' --exclude='.Trash-1000' /media/blueray/WDRed /media/blueray/WDPurple
如果我使用
--delete-after
rsync 將移動的目錄視為已刪除和創建的目錄。結果,當我在源中移動目錄時,它會從目標中刪除這些目錄,然後從源中複製它們。通常需要很長時間,因為我有時會在原始碼中移動大目錄。
我發現這個問題的解決方案很少。
- 更新檔 rsync。
- 沒有更新檔。
- 使用 BorgBackup 或 bup
- 利用
--fuzzy --delay-updates --delete-delay
然而,每個人都有自己的問題。
該更新檔是很久以前創建的,我不確定它是否會與現代 rsync 有問題。此外,維護更新檔對我來說很困難。
選項二在我的硬碟中造成混亂。此外,我使用了更多
rsync
選項,不確定它是否安全。就選項 3 而言,我投入了大量時間,
rsync
現在不想轉向新工具。此外,這些工具也有其自身的問題。關於選項 4,使用
--fuzzy --delay-updates --delete-delay
/test/10GBfile 重命名為 /test/otherdir/10GBfile_newname 仍會重新發送數據,因為它不在同一目錄中。它還有很多問題。前任。--delay-updates
與 衝突--inplace
。所以,我正在尋找的解決方案是**使用
--itemize-changes
並--dry-run
獲取移動的目錄列表,然後首先mv
在目標中執行(如果它有一個提示,比如 x 將被移動到目的地的 a/x,y 將是移動到 b/y in destination, c/z 將移動到 z in destination. 你要繼續嗎?) 然後執行我rsync
在頂部提到的命令。**我準備考慮與類似目錄具有相同名稱和大小的目錄。假設目錄樹如下所示:
. ├── dest │ ├── test │ │ └── empty-asciidoc-document.adoc │ ├── test2 │ │ └── empty-asciidoc-document.adoc │ └── test3 │ └── empty-asciidoc-document.adoc ├── src │ ├── grandpartest1 │ │ └── partest │ │ └── test1 │ │ └── empty-asciidoc-document.adoc │ ├── grandpartest2 │ │ └── partest2 │ │ └── test2 │ │ └── empty-asciidoc-document.adoc │ └── grandpartest3 │ └── partest3 │ └── test3 │ └── empty-asciidoc-document.adoc
我注意到,如果我移動目錄,
--itemize-changes
輸出看起來像:% rsync --dry-run -ai --inplace --delete-after /home/blueray/Downloads/src/ /home/blueray/Downloads/dest/ .d..t...... ./ cd+++++++++ grandpartest/ cd+++++++++ grandpartest/partest/ cd+++++++++ grandpartest/partest/test/ >f+++++++++ grandpartest/partest/test/empty-asciidoc-document.adoc cd+++++++++ grandpartest2/ cd+++++++++ grandpartest2/partest2/ cd+++++++++ grandpartest2/partest2/test2/ >f+++++++++ grandpartest2/partest2/test2/empty-asciidoc-document.adoc cd+++++++++ grandpartest3/ cd+++++++++ grandpartest3/partest3/ cd+++++++++ grandpartest3/partest3/test3/ >f+++++++++ grandpartest3/partest3/test3/empty-asciidoc-document.adoc *deleting test3/empty-asciidoc-document.adoc *deleting test3/ *deleting test2/empty-asciidoc-document.adoc *deleting test2/ *deleting test/empty-asciidoc-document.adoc *deleting test/
我們可以使用以下方法獲取已刪除的目錄:
% echo "$dryrunoutput" | grep "*deleting.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done test3 test2 test
添加目錄使用:
% echo "$dryrunoutput" | grep "cd++.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done | while read spo; do echo ${spo##*/}; done grandpartest partest test grandpartest2 partest2 test2 grandpartest3 partest3 test3
使用以下命令添加和刪除的目錄:
$ sort <(echo "$deletedirectories") <(echo "$addeddirectoriesvalue") | uniq -d test test2 test3
以字節為單位的目錄大小,比較兩者是相同的目錄(或多或少,這對我有用),使用:
% /usr/bin/du -sb "/home/blueray/Documents/src/test2/test" | grep -oh "^\S*" 4096 % /usr/bin/du -sb "/home/blueray/Documents/dest/test" | grep -oh "^\S*" 4096
到目前為止我想出的腳本是:
#!/bin/bash source="/media/blueray/WDRed/_working/_scripts/_rsync-test/src/" destination="/media/blueray/WDRed/_working/_scripts/_rsync-test/dest/" dryrunoutput=$(rsync --dry-run -ai --inplace --delete-after $source $destination) deletedirectories=$( echo "$dryrunoutput" | grep "*deleting.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done ) addeddirectorieskey=$( echo "$dryrunoutput" | grep "cd++.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done ) addeddirectoriesvalue=$( echo "$dryrunoutput" | grep "cd++.*/$" | awk '{print $2}' | while read spo; do echo ${spo%?}; done | while read spo; do echo ${spo##*/}; done ) intersection=$( sort <(echo "$deletedirectories") <(echo "$addeddirectoriesvalue") | uniq -d ) sourcesize=$(/usr/bin/du -sb "${source}test2/test" | grep -oh "^\S*") destsize=$(/usr/bin/du -sb "${destination}test" | grep -oh "^\S*") if [[ "$destsize" == "$sourcesize" ]] then mv "${destination}test/" "$destination$addeddirectories" fi
如果您注意到
mv "${destination}test/" "$destination$addeddirectories"
,這裡的部分路徑是硬編碼的。它還有其他問題。它僅適用於單個目錄和類似的東西。PS我知道相似的名稱和大小並不意味著它們相同,但在我的情況下它會起作用。我的目錄是主要問題,文件不是。所以,我並不擔心文件移動檢測。我只對目錄移動檢測感興趣。
您可以將此作為備份的基礎。它要求源文件系統和目標文件系統可以處理硬連結文件,並且您不介意目標文件在執行之間保持硬連結到工作目錄中。寫出文件的 inode 和相對路徑
find
的選項依賴於 GNU 的版本。-printf
#!/bin/bash # Usage: [<rsync_args...>] <src> <dst> # args=("$@") src="${args[-2]}" # '.' dst="${args[-1]}" # eg 'remote:/tmp/dest' unset args[-1] args[-1] # Yes really # Create the working set space # temp=".inodes" mkdir -p "$src/$temp" # Build the set of files indexed by inode # echo Create inodes >&2 find "$src" -path "$src/$temp" -prune -o -type f -printf "%i\t%P\0" | while IFS= read -d '' -r line do inode="${line%%$'\t'*}" file="${line#*$'\t'}" ln -f "$src/$file" "$src/$temp/$inode" done # Copy the index and then the full tree # echo Copy inodes >&2 rsync -avPR "${args[@]}" "$src/./$temp/" "$dst/" echo Copy structure >&2 rsync -avHPR --delete-after "${args[@]}" "$src/./$temp/" "$src/./" "$dst/" # Remove the working set on the source (not essential but you may prefer it) # echo Tidyup >&2 rm -rf "$src/$temp"
如果您呼叫它
dsync
並將其放入您的路徑中,您可以像這樣使用它dsync /media/blueray/WDRed /media/blueray/WDPurple
或可能
dsync --info=PROGRESS2,BACKUP,DEL --backup --human-readable --inplace --delete-after --log-file=/media/blueray/WDPurple/rsync.log --backup-dir=red_rsync_bak.$(date +"%d-%m-%y_%I-%M-%S%P") --log-file-format='%t %f %o %M' --exclude='lost+found' --exclude='.Trash-1000' /media/blueray/WDRed /media/blueray/WDPurple