
Мне нужно найти все файлы, которые существуют где-либо в dir1
, но не существуют где-либо в dir2
. dir1
и dir2
могут иметь другую структуру, поэтому diff -r
это не работает должным образом.
решение1
Попробуйте составить список файлов без пути. Таким образом, вы сможете сравнить два каталога. Однако имена файлов должны быть разными. Если у вас есть одно и то же имя файла, повторяющееся в dir1 в разных подкаталогах, удаление пути уберет уникальность имени файла. Вы можете получить список каждого каталога без путей, например:
find dir1/ -exec basename {} \; | sort
find dir2/ -exec basename {} \; | sort
Все вместе будет выглядеть примерно так
diff <(find dir1/ -exec basename {} \; | sort) <(find dir2/ -exec basename {} \; | sort)
Я вижу, что есть комментарий, предлагающий использовать fdupes. fdupes
Если это определенно лучшее решение.
решение2
Грубым методом может быть использование md5sum
. Только учтите, что файлы с нулевой длиной всегда будут рассматриваться как дубликаты, поэтому вам, возможно, захочется использовать find
только файлы с размером не менее одного байта.
find /first/path -type f -exec md5sum -b \{\} \; > /tmp/md5-path1.txt
cut -b1-32 < /tmp/md5-path1-short.txt
find /second/path -type f -exec md5sum -b \{\} \; > /tmp/md5-path2.txt
cut -b1-32 < /tmp/md5-path2-short.txt
Файлы в path1, которых нет в path2 (удалите опцию '-v')
grep /tmp/md5-path1.txt -v -F -f /tmp/md5/path2-short.txt
Уровень CYA: профессиональный
32 выше — это потому, что хэши MD5 имеют длину 32 байта. Если бы вы использовали, скажем, sha1sum
, что имеет еще меньшую вероятность коллизий, то вы бы использовали длину 40; sha224sum
требует 56, sha256sum
требует 64 и sha512sum
128.
Уровень CYA: параноидальный
Это может не работать в некоторых схемах кэширования, в которых метаданные хранятся в файлах.имя которого содержит хэш исходного файла.
(Это на самом деле произошло со мной несколько лет назад при установке Wordpress + Magento, когда мы хотели перенести огромный кэш статей, удалив при этом устаревшие записи).
В этом случае вам придется использовать другую схему хеширования — быстрое исправление — чтобы избежать grep
возврата ложных срабатываний, ошибочно принимая запись метаданных за исходный файл (поэтому используйте SHA1, если кэш использует MD5, или наоборот); или использовать sed
для переписывания всех строк в «коротких» файлах, чтобы добавить «^» в начале, таким образом превратив его в закрепленное регулярное выражение, и снять флаг -F
с grep
для обработки файла как регулярных выражений, а не как простых строк.
решение3
Итак, частичное решение, которое я нашел, это:
find dir1 -type f | grep -vxFf <(fdupes -r dir1 dir2)
но я говорю «частично», потому что если в , то они не будут показаны, поэтому сначала dir1
нужно запустить .fdupes -r dir1