如何刪除目錄中的重複檔案?

如何刪除目錄中的重複檔案?

我在一個目錄中下載了很多圖像。
下載程式重新命名了已存在的檔案。
我還手動重命名了一些文件。

a.jpg
b.jpg
b(2).jpg
hello.jpg      <-- manually renamed `b(3).jpg`
c.jpg
c(2).jpg
world.jpg      <-- manually renamed `d.jpg`
d(2).jpg
d(3).jpg

如何刪除重複的?結果應該是:

a.jpg
b.jpg
c.jpg
world.jpg

注意:名字並不重要。我只想要 uniq 檔。

答案1

bash 4.x

#!/bin/bash
declare -A arr
shopt -s globstar

for file in **; do
  [[ -f "$file" ]] || continue
   
  read cksm _ < <(md5sum "$file")
  if ((arr[$cksm]++)); then 
    echo "rm $file"
  fi
done

這既是遞歸的又可以處理任何檔案名稱。缺點是它需要 4.x 版本才能使用關聯數組和遞歸搜尋。echo如果您喜歡結果,請刪除。

呆呆版本

gawk '
  {
    cmd="md5sum " q FILENAME q
    cmd | getline cksm
    close(cmd)
    sub(/ .*$/,"",cksm)
    if(a[cksm]++){
      cmd="echo rm " q FILENAME q
      system(cmd)
      close(cmd)
    }
    nextfile
  }' q='"' *

請注意,這仍然會破壞名稱中包含雙引號的檔案。沒有真正的方法可以解決這個問題awkecho如果您喜歡結果,請刪除。

答案2

複製品是您選擇的工具。若要尋找目前目錄中的所有重複檔案(按內容,而不是按名稱):

fdupes -r .

若要手動確認刪除重複檔案:

fdupes -r -d .

自動刪除除每個重複檔案的第一個之外的所有副本 (請注意,此警告實際上會根據要求刪除文件):

fdupes -r -f . | grep -v '^$' | xargs rm -v

我建議在刪除之前手動檢查文件:

fdupes -rf . | grep -v '^$' > files
... # check files
xargs -a files rm -v

答案3

我建議氟克隆

Fclones 是一款用 Rust 編寫的現代重複文件查找器和刪除器,可在大多數 Linux 發行版和 macOS 上使用。

顯著特點:

  • 支援檔案路徑中的空格、非 ASCII 和控製字符
  • 允許在多個目錄樹中搜尋
  • 尊重 .gitignore 文件
  • 安全性:允許在對重複項執行任何操作之前手動檢查重複項列表
  • 提供了大量用於過濾/選擇要刪除或保留的檔案的選項
  • 非常快

要在目前目錄中搜尋重複項,只需執行:

fclones group . >dupes.txt

然後您可以檢查該dupes.txt檔案以檢查是否找到了正確的重複項(您也可以根據自己的喜好修改該清單)。

最後使用以下之一刪除/連結/移動重複檔案:

fclones remove <dupes.txt
fclones link <dupes.txt
fclones move target <dupes.txt
fclones dedupe <dupes.txt   # copy-on-write deduplication on some filesystems

例子:

pkolaczk@p5520:~/Temp$ mkdir files
pkolaczk@p5520:~/Temp$ echo foo >files/foo1.txt
pkolaczk@p5520:~/Temp$ echo foo >files/foo2.txt
pkolaczk@p5520:~/Temp$ echo foo >files/foo3.txt

pkolaczk@p5520:~/Temp$ fclones group files >dupes.txt
[2022-05-13 18:48:25.608] fclones:  info: Started grouping
[2022-05-13 18:48:25.613] fclones:  info: Scanned 4 file entries
[2022-05-13 18:48:25.613] fclones:  info: Found 3 (12 B) files matching selection criteria
[2022-05-13 18:48:25.614] fclones:  info: Found 2 (8 B) candidates after grouping by size
[2022-05-13 18:48:25.614] fclones:  info: Found 2 (8 B) candidates after grouping by paths and file identifiers
[2022-05-13 18:48:25.619] fclones:  info: Found 2 (8 B) candidates after grouping by prefix
[2022-05-13 18:48:25.620] fclones:  info: Found 2 (8 B) candidates after grouping by suffix
[2022-05-13 18:48:25.620] fclones:  info: Found 2 (8 B) redundant files

pkolaczk@p5520:~/Temp$ cat dupes.txt
# Report by fclones 0.24.0
# Timestamp: 2022-05-13 18:48:25.621 +0200
# Command: fclones group files
# Base dir: /home/pkolaczk/Temp
# Total: 12 B (12 B) in 3 files in 1 groups
# Redundant: 8 B (8 B) in 2 files
# Missing: 0 B (0 B) in 0 files
6109f093b3fd5eb1060989c990d1226f, 4 B (4 B) * 3:
    /home/pkolaczk/Temp/files/foo1.txt
    /home/pkolaczk/Temp/files/foo2.txt
    /home/pkolaczk/Temp/files/foo3.txt

pkolaczk@p5520:~/Temp$ fclones remove <dupes.txt
[2022-05-13 18:48:41.002] fclones:  info: Started deduplicating
[2022-05-13 18:48:41.003] fclones:  info: Processed 2 files and reclaimed 8 B space

pkolaczk@p5520:~/Temp$ ls files
foo1.txt

答案4

如何測試具有獨特內容的文件?

if diff "$file1" "$file2" > /dev/null; then
    ...

我們如何取得目錄中的檔案清單?

files="$( find ${files_dir} -type f )"

我們可以從該清單中取得任意 2 個文件,並檢查它們的名稱是否不同且內容是否相同。

#!/bin/bash
# removeDuplicates.sh

files_dir=$1
if [[ -z "$files_dir" ]]; then
    echo "Error: files dir is undefined"
fi

files="$( find ${files_dir} -type f )"
for file1 in $files; do
    for file2 in $files; do
        # echo "checking $file1 and $file2"
        if [[ "$file1" != "$file2" && -e "$file1" && -e "$file2" ]]; then
            if diff "$file1" "$file2" > /dev/null; then
                echo "$file1 and $file2 are duplicates"
                rm -v "$file2"
            fi
        fi
    done
done

例如,我們有一些目錄:

$> ls .tmp -1
all(2).txt
all.txt
file
text
text(2)

所以只有 3 個獨特的文件。

讓我們運行該腳本:

$> ./removeDuplicates.sh .tmp/
.tmp/text(2) and .tmp/text are duplicates
removed `.tmp/text'
.tmp/all.txt and .tmp/all(2).txt are duplicates
removed `.tmp/all(2).txt'

我們只剩下 3 個文件了。

$> ls .tmp/ -1
all.txt
file
text(2)

相關內容