
Я ищу решение для Linux следующей проблемы:
Даны два каталога с большим количеством файлов. Все имена файлов случайны и различны в обоих каталогах. Однако содержимое некоторых файлов в двух каталогах идентично.
Я хочу скопировать все файлы, которые встречаются в обоих каталогах, в третий каталог. («Присутствуют в обоих» означает иметь одинаковое содержимое, а не одинаковое имя.)
решение1
Если предположить, что имена ваших файлов не содержат пробелов и в обоих каталогах нет подкаталогов, то следующая команда выведет пары имен файлов с совпадающими суммами MD5:
join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort)
Чтобы получить только одно из имен файлов, используйте -o 1.2
или -o 2.2
.
Если имена файлов (или пути) могут содержать пробелы, вам придется действовать более разумно.
Если в одном каталоге может быть один и тот же файл с несколькими именами, вам также нужно будет быть умнее — и вам нужно будет решить, что именно делать. Одной из возможностей будет отфильтровать дубликаты перед выполнением объединения:
join -o 1.2,2.2 <(md5sum $D1/* | sort | uniq -w16) \
<(md5sum $D2/* | sort | uniq -w16)
НЕ ИСПОЛЬЗОВАТЬsum
sum
выводит 16-битную контрольную сумму; если у вас есть хотя бы пара сотен файлов в каждом каталоге, то, скорее всего, вы получите ложный положительный результат, если сравните 16-битные контрольные суммы. md5sum
также не является абсолютно безопасным, но вероятность столкновения с 128-битными контрольными суммами мала. В случае сомнений, и если это действительно важно, cmp
файлы также:
join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort) |
while read F1 F2; do
if cmp -s $F1 $F2; then
cp F1 $D3
fi
done
(Опять же, это не сработает, если в именах файлов есть пробелы.)
решение2
Используйте вашу любимую оболочку для этого псевдокода:
cd D1; sum * | while read l; do echo "D1 $l"; done >/tmp/foo
cd D2; sum * | while read l; do echo "D2 $1"; done >>/tmp/foo
sort -n /tmp/foo | awk '
$1 == prev_cs { echo "cp $3 dest"}
/prev_cs = $1/
' | shell
При желании вы можете сохранить вывод awk для просмотра перед отправкой копий.
решение3
это может сработать, как и в случае с ответами mpez0 по копированию дубликатов.
find {tst1,tst2} -exec sum {} {} \; 2> /dev/null | sort | uniq