使用 rsync 複製兩個大型目錄時,最穩妥的做法不是把兩個來源路徑隨手寫進一條命令,而是先明確每個來源目錄對應哪個目標目錄,再逐組執行:
|
|
每組任務都先用 --dry-run 預演,實際複製時保留未完成檔案並記錄日誌,複製結束後再執行一次只讀比對。
如果一般比對沒有輸出,說明 rsync 按檔案大小、修改時間和相關屬性沒有發現差異;如果要確認檔案內容也一致,再增加 --checksum 做全量讀取驗證。
可以直接採用的安全方案
下面假設來源磁碟和目標磁碟都已正確掛載:
|
|
先建立目標目錄:
|
|
分別預演兩組同步:
|
|
確認源、目標路徑和變更清單都正確後,去掉 -n,依序執行實際同步:
|
|
第一次遷移建議不要新增 --delete。
這樣即使目標目錄中有額外檔案,rsync 也不會刪除它們。等目錄結構和驗證結果都確認無誤後,再決定是否需要把目標做成源的完全鏡像。
為什麼兩個目錄最好分兩次執行
rsync 的最後一個位置參數是目標目錄,前面的參數都被視為源。
下面這種寫法:
|
|
表示把兩個源都匯入同一個 /target/,並不表示 /source/a/ 對應 /target/a/、/source/b/ 對應 /target/b/。
當兩個目錄需要分別落到兩個目標路徑時,應執行兩次 rsync,或者寫一個明確的序列腳本。
分開執行還有幾個實際好處:
- 每個目錄有獨立日誌和退出狀態;
- 某一組失敗時,不會掩蓋另一組的結果;
- 驗證時可以逐組定位差異;
- 可以讓機械硬碟順序讀寫,避免兩個任務爭搶磁頭;
- 能為不同目錄設定不同的排除規則。
如果兩個源確實要匯入同一個目標,先確認它們是否包含同名相對路徑。
例如兩個源都有 2026/report.pdf,後執行的源可能覆蓋先執行的同名檔案。此時更安全的做法是為它們保留獨立子目錄。
先確認掛載點,避免複製到系統磁碟
大目錄遷移最危險的錯誤之一,是目標磁碟沒有掛載成功,但目標路徑仍然存在。
此時 rsync 會把資料寫進根檔案系統中的普通目錄,直到系統磁碟被寫滿。
開始前檢查塊裝置、檔案系統和掛載點:
|
|
重點確認:
/mnt/disk1和/mnt/disk2對應預期裝置;- 目標磁碟可用空間足夠;
- 目標掛載不是隻讀狀態;
- 兩個路徑不是意外指向同一個檔案系統位置;
- 目標路徑不是來源路徑內部的子目錄。
可以用下面的命令檢視解析後的真實路徑:
|
|
再做一個小型寫入測試:
|
|
這裡只刪除剛剛明確建立的測試檔案,不要用萬用字元清理目標目錄。
目錄末尾斜槓決定複製層級
這兩條命令的結果不同:
|
|
第一條複製 /source/ 裡面的內容:
|
|
第二條複製 source 目錄本身:
|
|
同步兩個已經建立好的對應目錄時,通常在來源路徑和目標路徑後都寫 /:
|
|
不要只憑目錄名稱猜測結果。第一次執行前用 --dry-run --itemize-changes 檢視將建立的相對路徑。
每個推薦參數分別解決什麼問題
基礎參數組合是:
|
|
其中:
| 參數 | 作用 | 注意事項 |
|---|---|---|
-a |
歸檔模式,遞迴併保留常見屬性 | 不等於自動保留所有硬連結、ACL 和延伸屬性 |
-H |
保留硬連結關係 | 大量硬連結會增加記憶體消耗 |
-A |
保留 POSIX ACL | 目標檔案系統必須支援 ACL |
-X |
保留延伸屬性 | 目標檔案系統必須支援 xattr |
--numeric-ids |
直接保留 UID、GID 數值 | 適合 Linux 磁碟遷移和系統資料複製 |
--partial |
中斷後保留未傳完的檔案 | 下次執行仍會檢查並繼續傳輸 |
--partial-dir=.rsync-partial |
把未完成檔案放進專用目錄 | 驗證完成前不要手動刪除該目錄 |
--info=progress2 |
顯示整個任務的整體進度 | 統計總量會隨檔案清單生成方式變化 |
--info=stats2 |
結束時顯示傳輸統計 | 不能替代複製後的獨立驗證 |
--log-file |
把詳細記錄寫入日誌 | 日誌目錄必須可寫 |
如果複製的是一般文件、照片和影片,而且來源目錄沒有硬連結、ACL 或延伸屬性,可以按實際需求減少參數。
不要機械地認為參數越多越安全。
例如目標是 FAT、exFAT 或某些網路檔案系統時,權限、所有者、ACL、xattr 可能無法完整儲存,-A、-X 或所有者設定可能報錯。
先檢視兩端檔案系統類型:
|
|
如果兩端能力不同,應先明確需要保留的是檔案內容,還是完整的 Linux 後設資料。
增量同步到底會複製什麼
預設情況下,rsync 主要根據檔案大小和修改時間判斷檔案是否需要更新。
再次執行相同命令時:
- 新檔案會被複制;
- 大小或修改時間變化的檔案會被更新;
- 沒有變化的檔案會被跳過;
- 目標獨有檔案會保留;
- 中斷的檔案會按照當前狀態重新檢查並繼續處理。
這就是增量同步適合大目錄遷移的原因。
但它不是檔案系統快照。
如果來源目錄在複製過程中持續變化,最後得到的目標可能包含不同時間點的檔案狀態。普通照片庫或歸檔目錄可以在首次複製後再執行一次增量補齊;資料庫、虛擬機器鏡像和正在寫入的應用資料應先停止服務、凍結寫入或使用檔案系統快照。
預演時怎樣閱讀變更清單
推薦的預演命令是:
|
|
-n 是 --dry-run 的短寫,只計算計劃,不寫入檔案。
--itemize-changes 會顯示每個變化項及原因。常見輸出形式包括:
|
|
大致可以這樣理解:
>f+++++++++:目標中沒有該檔案,將新建;>f開頭且後面有屬性標記:檔案內容或屬性將更新;.d:目錄本身的屬性需要調整;*deleting:配合--delete時,目標獨有內容將被刪除。
如果預演中出現意外的頂層目錄名,通常是來源路徑末尾 / 寫錯。
如果幾乎所有大檔案都顯示要重傳,應檢查兩端時間、檔案系統時間精度、掛載參數,以及檔案是否被應用持續改寫。
用腳本依序同步兩個目錄
需要重複執行時,可以儲存為 /usr/local/sbin/sync-two-dirs.sh:
|
|
賦予執行權限並執行:
|
|
腳本使用 set -Eeuo pipefail。
如果第一組 rsync 回傳非零狀態,腳本會停止,不會把整體任務誤報為成功。處理完錯誤後重新執行即可,已經一致的檔案會被跳過。
在 tmux 中執行長時間任務
數 TB 資料可能需要數小時甚至數天。推薦在 tmux 中執行,而不是依賴一直開啟的 SSH 視窗:
|
|
進入會話後執行:
|
|
按 Ctrl+b,再按 d,可以讓會話在後臺繼續。
重新連線:
|
|
同時可以從另一個終端觀察日誌:
|
|
檢查程序:
|
|
不要同時啟動多個相同腳本。兩個任務寫入同一塊機械硬碟時,並行複製通常只會增加隨機尋道和等待時間。
如何確認 rsync 本身正常結束
命令結束後首先檢查退出狀態:
|
|
0 表示本次執行沒有檢測到錯誤,但不能單獨證明每個檔案內容都經過完整驗證。
常見非零狀態包括:
| 狀態碼 | 常見含義 | 處理方向 |
|---|---|---|
11 |
檔案 I/O 錯誤 | 檢視核心日誌、磁碟和檔案系統狀態 |
12 |
rsync 協議資料流錯誤 | 檢查遠端連線、版本和日誌 |
23 |
部分檔案未傳輸 | 搜尋權限、消失檔案、xattr 和 I/O 報錯 |
24 |
原始檔在傳輸中消失 | 判斷是否有程式正在移動或刪除檔案 |
30 |
資料傳輸超時 | 檢查網路、SSH 和超時參數 |
檢視日誌末尾:
|
|
不要只看終端最後出現了“總位元組數”。日誌中如果存在 IO error、Permission denied、failed 或 vanished file,仍需判斷是否影響驗收。
第一層驗證:再次執行 dry-run
實際複製後,對兩組目錄分別執行:
|
|
這裡同時使用了 -n,所以 --delete 只會報告目標端多餘內容,不會真的刪除。
沒有輸出通常表示:
- rsync 沒有發現需要新增或更新的檔案;
- 目標端沒有來源端不存在的額外路徑;
- 本次要求保留的常見屬性沒有差異。
如果輸出只有 .rsync-partial/,先確認沒有未完成任務。所有同步和驗證都結束後,再決定是否清理該臨時目錄。
如果輸出包含 *deleting,說明目標中有來源目錄沒有的檔案。先核對這些檔案是否應該保留,不要立刻去掉 -n。
第二層驗證:讀取兩端內容並計算雜湊值
普通 dry-run 主要依賴大小和修改時間,不能排除“大小和時間相同但內容不同”的少見情況。
嚴格驗證可以使用:
|
|
其中 -c 等同於 --checksum。
它會讀取雙方檔案內容並計算checksum,而不是僅比較大小和修改時間。因為同時帶有 -n,發現差異時只報告,不修正,也不會刪除檔案。
對數 TB 資料執行 -c 可能需要很長時間,並對來源磁碟和目標磁碟產生一輪完整讀取負載。
適合使用嚴格驗證的場景包括:
- 原磁碟出現過讀錯誤或掉盤;
- 遷移經過不穩定網路;
- 檔案內容非常重要且沒有其他驗證機制;
- 需要在離線來源磁碟前完成最終驗收;
- 懷疑目標檔案系統或記憶體導致靜默損壞。
如果磁碟健康狀況不佳,先檢查 SMART 和核心日誌,不要為了驗證反覆讀取瀕臨故障的磁碟。
第三層驗證:比較檔案數量與邏輯位元組數
統計普通檔案數量:
|
|
統計普通檔案的邏輯大小總和:
|
|
-xdev 表示不進入目錄下掛載的其他檔案系統。
如果來源目錄本來就包含巢狀掛載點,而這些內容也應該複製,就不能直接使用 -xdev,並且要確認 rsync 的掛載點處理策略符合預期。
檔案數量和邏輯位元組數相等只能作為輔助證據,不能證明路徑和內容逐一一致。
du -sh 更不能作為唯一驗收依據,因為稀疏檔案、壓縮、去重、塊大小、硬連結和檔案系統後設資料都會影響實際佔用空間。
產生 SHA-256 清單進行獨立驗證
如果希望儲存可審計的內容清單,可以在每個目錄內部按相對路徑計算 SHA-256:
|
|
第二組目錄同樣處理:
|
|
diff 沒有輸出且退出狀態為 0,表示兩份清單一致。
這仍然只驗證普通檔案內容和相對路徑,不驗證目錄權限、ACL、所有者、硬連結關係或延伸屬性。完整 Linux 資料遷移應把它與 rsync -aHAXnc 的結果結合起來看。
檢查權限、ACL、延伸屬性與硬連結
抽查關鍵檔案的基本屬性:
|
|
檢查 ACL:
|
|
檢查延伸屬性:
|
|
檢查硬連結檔案的 inode 和連結數:
|
|
來源端和目標端的 inode 數字不需要相同,但同一端內原本屬於一組硬連結的檔案,應該共享 inode,並保留正確的連結數。
什麼時候才使用 –delete
--delete 讓目標最終與源保持鏡像關係:目標中存在、源中不存在的路徑會被刪除。
先做只讀預演:
|
|
注意:--delete-delay 也會啟用刪除語義,只是把實際刪除推遲到傳輸結束階段。
實際鏡像前至少確認:
- 源和目標沒有寫反;
- 目標掛載點確實線上;
- dry-run 中的每個
*deleting都符合預期; - 目標端沒有需要獨立保留的檔案;
- 已有另一份可恢復備份。
如果希望刪除仍可回看,可以先使用備份目錄:
|
|
備份目錄必須位於空間足夠的位置,並且不能放進會再次被同步的來源目錄樹中。
排除回收站和臨時目錄
NAS 或桌面磁碟中常見一些不需要遷移的快取目錄。僅在確認它們確實可丟棄後新增排除規則:
|
|
'#recycle/' 必須加引號,否則 Shell 可能把 # 後面的內容視為註釋。
實際命令和驗證命令必須使用相同的排除規則,否則驗證時會把有意忽略的內容報告為缺失。
排除規則較多時,儲存到檔案:
|
|
然後使用:
|
|
控制磁碟和網路負載
在生產伺服器上遷移大目錄時,可以降低程序的 CPU 和 I/O 優先順序:
|
|
跨網路傳輸還可以限速。遠端目標建議直接寫出絕對路徑,避免混淆本地變數和遠端路徑:
|
|
本地磁碟到本地磁碟通常不需要 -z 壓縮。照片、影片、壓縮包也很難進一步壓縮,開啟 -z 只會增加 CPU 負擔。
常見失敗與處理方法
Permission denied
先在日誌中確認是讀取原始檔失敗、建立目標檔案失敗,還是設定所有者、ACL、xattr 失敗。
|
|
不要直接對整個目標執行寬泛的 chmod -R 777。應檢查掛載選項、目標目錄所有者和目標檔案系統能力。
No space left on device
同時檢查容量和 inode:
|
|
大量小檔案可能先耗盡 inode,即使 df -h 仍顯示有可用容量。
Input/output error
立即檢視核心和磁碟狀態:
|
|
把 /dev/sdX 替換為實際裝置。出現持續讀錯誤時,應先保護仍可讀取的資料,不要反覆執行全盤驗證增加故障盤壓力。
file has vanished
狀態碼 24 通常表示掃描後、複製前,原始檔被移動或刪除。
快取、日誌和下載目錄中偶爾出現這種情況並不罕見。對需要一致性的業務目錄,應暫停寫入或從快照複製,然後重新執行並確認不再出現消失檔案。
所有檔案都被再次傳輸
常見原因包括:
- 目標檔案系統不能保留來源端時間精度;
- 應用在複製後又改寫了檔案;
- 源和目標時鐘異常;
- 使用了會改變檔案屬性的掛載方式;
- 檔案經過中間程式重新編碼或重新打包。
先用 --dry-run --itemize-changes 觀察究竟是內容、大小、時間還是權限觸發更新。
最終驗收清單
完成兩個大目錄遷移後,至少保留以下證據:
- 兩條實際
rsync命令均回傳0; - 兩份日誌中沒有未處理的 I/O、權限或空間錯誤;
- 兩組普通 dry-run 都沒有意外輸出;
- 如需鏡像,帶
--delete的 dry-run 沒有意外刪除項; - 檔案數量和邏輯位元組數相符;
- 重要資料完成
rsync -nc或獨立 SHA-256 驗證; - 關鍵檔案能夠從目標端實際開啟;
- 權限、ACL、xattr 和硬連結按業務需求保留;
- 來源磁碟在驗收完成前沒有被格式化或離線;
- 有條件時完成一次從目標端恢復檔案的演練。
最實用的確認命令仍然是:
|
|
它沒有輸出時,表示在當前排除規則和參數範圍內,rsync 沒有發現內容、路徑或相關屬性差異。
對於數 TB 的資料,嚴格驗證很慢是正常現象。不要因為複製命令顯示 100% 就立刻刪除來源資料;複製完成、驗證透過和可恢復驗證是三個不同的階段。
常見問題
中斷後需要新增特殊的“續傳”命令嗎?
通常不需要。重新執行相同的 rsync 命令即可。--partial --partial-dir=.rsync-partial 會保留未完成資料,已經一致的檔案會被跳過。
兩個大目錄可以並行複製嗎?
技術上可以,但如果它們位於同一來源磁碟或同一目標機械硬碟,並行任務往往會降低吞吐量。預設序列更容易記錄、重試和驗收。
--progress 和 --info=progress2 有什麼區別?
--progress 更偏向顯示當前檔案進度,--info=progress2 顯示整個傳輸任務的整體進度。超大目錄通常後者更便於觀察。
為什麼複製完成後兩邊 du -sh 不一樣?
檔案系統塊大小、稀疏檔案、壓縮、硬連結、後設資料和保留塊都可能導致佔用不同。優先看 rsync 比對、檔案清單和內容驗證,不要只看 du。
rsync -nc 會修改目標檔案嗎?
不會。-n 是 dry-run,-c 只是要求根據檔案內容checksum判斷差異。命令會大量讀取磁碟,但不會執行複製或刪除。
驗證時為什麼仍要加上 --delete?
因為只比較源中存在的檔案,無法發現目標端多出來的路徑。與 -n 同時使用時,--delete 只報告這些額外內容,不會真的刪除。
什麼時候可以刪除來源目錄?
至少等到兩組同步退出狀態正常、日誌無未解決錯誤、嚴格驗證透過,並從目標端成功開啟或恢復關鍵檔案之後。重要資料還應保留另一份獨立備份。