Shell-Script

使用腳本/rsync 命令幫助在刪除源文件之前使用 md5 和比較移動文件/

  • July 11, 2018

參考這篇文章來查找和刪除基於校驗和的重複文件,我想修改執行複制操作的方法,然後對目標文件進行文件完整性檢查。

SOURCE = /path/to/Source
DEST = /path/to/Destination
# filecksums containing the md5 of the copied files
declare -A filecksums

for file in "$@"
do
   [[ -f "$file" ]] || continue

   # Generate the checksum
   cksum=$(cksum <"$file" | tr ' ' _)

   # Can an exact duplicate be found in the destination directory?
   if [[ -n "${filecksums[$cksum]}" ]] && [[ "${filecksums[$cksum]}" != "$file" ]]
   then
       rm -f "$file"
   else
       echo " '$file' is not in '$DEST'" >&2
   fi
done

我想使用 md5 校驗和比較的結果,rm -f僅當校驗和相等時才允許源文件。如果有區別,我想回顯結果並轉義。rsync可能是另一種選擇,但我認為我會在強制進行本地-本地文件傳輸的校驗和比較時遇到問題。

更新 我已經研究過根據@Lucas 的回答使用 rsync 。似乎有一些選項可以通過檢查而不是批量傳輸文件更穩定地傳輸文件,mv /data1/* /data2/並在檢查後報告所做的事情和刪除。這可能會縮小社區成員所指出的定義。

如果您關心文件並且不想搞砸,那麼第一次嘗試實施這樣的事情可能會很困難。所以這裡有一些在 bash 中編寫完整腳本的替代方法。這些或多或少是複雜的命令行(oneliners),可能對您的情況有所幫助。

你的問題有一個不確定性:你想比較source 中的每個文件與 dest 中的**每個文件還是只比較那些具有“匹配”文件名的文件?(這將/path/to/src/a/path/to/dest/a/path/to/src/b/path/to/dest/b而不是/path/to/src/a/path/to/dest/b等等進行比較)

我假設您只想比較具有匹配路徑的文件!

第一個想法:diff

好老diff可以遞歸地比較目錄。還可以使用該-q選項來查看哪些文件不同,而不是它們有何不同。

diff -r -q /path/to/source /path/to/dest

缺點

  • 這可能需要很長時間,具體取決於硬碟的大小。
  • 這不會刪除舊文件。
  • 輸出我不容易解析

優點

  • 這不會刪除任何文件:)

因此,在您手動/視覺確認您關心的任何文件沒有差異之後,您必須手動刪除帶有rm -rf /path/to/source.

第二個想法:(rsync編輯:這可能是現在最好的)

rsync是所有複製命令行工具的大師(在我看來;)。正如對您問題的評論中提到的,它有一個--checksum選項,但它也有大量其他選項。它可以將文件從本地傳輸到遠端,從遠端傳輸到本地,從本地傳輸到本地。我認為最重要的功能之一是,如果您提供正確的選項,您可以中止並重新啟動命令(再次執行相同的命令行),它將繼續從它離開的地方!

出於您的目的,以下選項可能很有趣:

  • -v:詳細,顯示發生的情況可以多次給出,但通常一次就足夠了
  • -n: 試執行,測試東西很重要,但什麼都不做(結合-v)!!
  • -c: 使用校驗和來決定應該複製什麼
  • --remove-source-files:刪除成功傳輸的文件(@brawny84 指出,我不知道,並且在我第一次閱讀時在手冊頁中沒有找到它)

所以這個命令將覆蓋所有dest校驗和與對應文件不同的文件source(按名稱對應)。

rsync -a -c -v --remove-source-files -n /path/to/source /path/to/dest
rsync -a -c -v --remove-source-files    /path/to/source /path/to/dest

優點

  • 與校驗和一起使用
  • 有空執行模式
  • 實際上會將所有失去的文件和與源不同的文件複製到目標
  • 可以中止並重新啟動
  • 如果您不想複製所有文件,則有一個排除選項可以忽略 src 中的某些文件
  • 可以刪除傳輸的源文件

缺點

  • ??

第三個想法:fdupes

fdupes我設計的用於列出重複文件的程序。它預設檢查 md5sums。

優點

  • 它使用 md5 比較文件
  • 它可以--delete選擇刪除其中一個重複項

缺點

  • 它將每個文件與每個其他文件進行比較,因此如果 dest 本身內部有重複文件,它也會列出它們
  • 刪除模式似乎是互動式的,您必須確認每組相等的文件,這對於大型目錄樹可能不可行
  • 非互動模式將從每組相等的文件中刪除除第一個文件之外的所有文件。但我不知道第一個文件是哪個(在源文件中還是在目標文件中?)

最後一個想法:經歷實際編寫和調試自己的 shell 腳本的痛苦

如果必須手動完成,我會從這樣的事情開始。 我沒有對此進行測試,ls先嘗試一下,然後嘗試弄清楚它是否會剎車!!

#!/bin/bash
# first require that the source and dest dirs
# are given as arguments to the script.
src=${1:?Please give the source dir as first argument}
dest=${2:?Please give the destination dir as second argument}
# go to the source directory
cd "$src"
# This assumes that there are no newlines in filenames!
# first find all plain files in the current dir 
# (which should be $src)
# then use xargs to hand the filenames to md5sum 
# pipe the md5 sums into a subshell
# go to the dest in the subshell
# read the md5sums from stdin and use md5sum -c to check them 
# After the subshell filter lines to only keep those that end in "OK"
# and at the same time remove the "OK" stuff after the file name
# use xargs to hand these file names to ls or rm.
find . -type f | \
 xargs md5sum | \
 ( cd "$dest" && md5sum -c ) | \
 sed -n 's/: OK$//p' | \
 xargs ls

最後ls一行是列出所有通過檢查的文件。如果您將其替換為,rm它們將從源目錄( 之後的目前目錄cd "$src")中刪除。

引用自:https://unix.stackexchange.com/questions/454547