25

Я скачал много изображений в каталоге.
Загрузчик переименовал файлы, которые уже существуют.
Я также переименовал некоторые файлы вручную.

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

примечание: имя не имеет значения. Я просто хочу уникальные файлы.

11 ответов11

39

fdupes - инструмент по вашему выбору. Чтобы найти все дубликаты файлов (по содержанию, а не по имени) в текущем каталоге:

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
24

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

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='"' *

Обратите внимание, что это все равно будет работать с файлами, в имени которых есть двойные кавычки. Нет реального способа обойти это с помощью awk . Уберите echo если вам нравятся результаты.

2

Вы можете попробовать FSLint. Он имеет как командную строку, так и графический интерфейс.

1

Я написал этот крошечный скрипт для удаления дублированных файлов

https://gist.github.com/crodas/d16a16c2474602ad725b

В основном он использует временный файл (/tmp/list.txt) для создания карты файлов и их хэшей. Позже я использую эти файлы и магию каналов Unix, чтобы сделать все остальное.

Скрипт ничего не удалит, но напечатает команды для удаления файлов.

mfilter.sh ./dir | bash

Надеюсь, поможет

1

Будучи немного ленивым, я быстро нашел его в Интернете.

Сначала вы должны создать контрольную сумму CRC для каждого файла, поскольку вы, очевидно, хотите удалить только точные дубликаты.

cksum  *.jpg | sort -n > filelist

Затем переберите этот список файлов, прочитав контрольную сумму, а также имя файла. Если две контрольные суммы совпадают, файл будет удален. Это работает, так как сортировка является числовой и сортирует только по контрольным суммам, которые группируют дубликаты файлов.

old=""
while read sum lines filename
do
      if [[ "$sum" != "$old" ]] ; then
            old="$sum"
            continue
      fi
      rm -f "$filename"
done < filelist

Очевидно, это не работает рекурсивно.

1

Как проверить файлы, имеющие уникальный контент?

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)
1

Более краткая версия удаления дублированных файлов (всего одна строка)

young@ubuntu-16:~/test$ md5sum `find ./ -type f` | sort -k1 | uniq -w32 -d | xargs rm -fv

find_same_size.sh

#!/usr/bin/env bash
#set -x
#This is small script can find same size of files.
find_same_size(){

if [[ -z $1 || ! -d $1 ]]
then
echo "Usage $0 directory_name" ;
 exit $?
else
dir_name=$1;
echo "current directory is $1"



for i in $(find $dir_name -type f); do
   ls -fl $i
done | awk '{f=""
        if(NF>9)for(i=9;i<=NF;i++)f=f?f" "$i:$i; else f=$9;
        if(a[$5]){ a[$5]=a[$5]"\n"f; b[$5]++;} else a[$5]=f} END{for(x     in b)print a[x] }' | xargs stat -c "%s  %n" #For just list files
 fi
   }

find_same_size $1


young@ubuntu-16:~/test$ bash find_same_size.sh tttt/ | awk '{ if($1 !~   /^([[:alpha:]])+/) print $2}' | xargs md5sum | uniq -w32 -d | xargs rm -vf
0

Это не то, что вы спрашиваете, но я думаю, что кто-то может найти это полезным, когда контрольные суммы не совпадают, но имя схоже (с суффиксом в скобках). Этот скрипт удаляет файлы с суффиксами как ("цифра")

#! /bin/bash
# Warning: globstar excludes hidden directories.
# Turn on recursive globbing (in this script) or exit if the option is not supported:
shopt -s globstar || exit
for f in **
do
extension="${f##*.}"
#get only files with parentheses suffix
FILEWITHPAR=$( echo "${f%.*}".$extension | grep -o -P "(.*\([0-9]\)\..*)")
# print file to be possibly deleted
if [ -z "$FILEWITHPAR" ] ;then
:
else
echo "$FILEWITHPAR ident"
# identify if a similar file without suffix exists
FILENOPAR=$(echo $FILEWITHPAR | sed -e 's/^\(.*\)([0-9])\(.*\).*/\1\2/')
echo "$FILENOPAR exists?"
if [ -f "$FILENOPAR" ]; then
#delete file with suffix in parentheses
echo ""$FILEWITHPAR" to be deleted"
rm -Rf "$FILEWITHPAR"
else
echo "no"
fi
fi
done
0

Я нашел более простой способ выполнить ту же задачу

for i in `md5sum * | sort -k1 | uniq -w32 -d|awk '{print $2}'`; do
rm -rf $i
done
0

Большинство и, возможно, все остальные ответы ужасно неэффективны из-за вычисления контрольной суммы каждого файла в каталоге для обработки.

Потенциально более быстрый подход заключается в том, чтобы сначала получить размер каждого файла, который является почти немедленным (ls или stat), а затем вычислить и сравнить контрольные суммы только для файлов, имеющих не уникальный размер.

-3

Я нашел небольшую программу, которая действительно упрощает такие задачи: fdupes.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .