Linux: Сравнение структуры каталогов без сравнения файлов

55

Каков наилучший и самый простой способ сравнения двух структур каталогов без фактического сравнения данных в файлах? Это прекрасно работает:

diff -qr dir1 dir2_

Но он очень медленный, потому что сравнивает файлы тоже. Для этого есть переключатель diff или другой простой инструмент cli?

Ион
источник
Под «структурой каталогов» вы подразумеваете только пути к каталогам или пути как к каталогу, так и к файлам вне каталога?
интуитивно
Да, папки и файлы.
Иона
1
В этом случае вы должны удалить -type dопцию из ответа @ slartibartfast или проверить мой ответ.
интуитивно

Ответы:

36

Следующее (если вы замените первый каталог на directory1, а второй на directory2) должно сделать то, что вы ищете, и быстро:

find directory1 -type d -printf "%P\n" | sort > file1
find directory2 -type d -printf "%P\n" | sort | diff - file1

Основополагающий принцип заключается в том, что он распечатывает все каталоги, включая пути к подкаталогам, относительно базовых каталоговN.

Это может упасть (привести к странным выводам), если у вас есть возврат каретки в некоторых именах каталогов, но нет других.

Слартибартфаст
источник
Это не очень хорошо для меня, потому что если один каталог содержит папку с несколькими тысячами файлов, они все перечислены по отдельности, в то время как diff -rqпросто показывает, что корневой каталог существует в одном и продолжает.
Крис Джефферсон
Как указывалось (несколько лет назад) интуитивно, чтобы ответить на вопрос OPs, нужно удалить -type d, чтобы файлы сравнивались как с каталогами, так и с пользователями
user2746401
Я понимаю и уважаю это прочтение постановки проблемы. Это было не мое чтение в то время. Вы рекомендуете отредактировать мой ответ, чтобы ответить на обновленный вопрос? Я в порядке, если вы думаете, что это будет полезно для некоторых людей, и я в порядке, оставляя решение и комментарии такими, какие они есть сейчас, что представляется достаточно эффективным.
Slartibartfast
34
vimdiff <(cd dir1; find . | sort) <(cd dir2; find . | sort)

предоставит вам хорошее параллельное отображение двух иерархий каталогов со сложенными общими разделами.

garyjohn
источник
Это решение дает сбой случайно. Когда vim читает (или перечитывает) временный файловый дескриптор, он уже пропал.
Денилсон Са Май
23

Я обычно использую rsyncдля этой задачи:

rsync -nav --delete DIR1/ DIR2

БУДЬТЕ ОЧЕНЬ ОСТОРОЖНЫ, чтобы всегда использоватьопцию-n, aka--dry-run, или она будет синхронизировать (изменять содержимое) каталогов.

При этом файлы будут сравниваться по времени и размеру файла ... Я думаю , это то, что вы действительно хотите, или, по крайней мере, вы не против, если это так? У меня есть ощущение, что вы просто хотите, чтобы это происходило быстрее , а не для того, чтобы игнорировать разницу между содержимым файлов. Если вы хотите, чтобы в нем не отображались разные файлы с одинаковыми именами, я думаю, что добавление --ignore-existingопции сделает это.

Также следует помнить , что не вводя /в конце DIR1заставит его сравнить каталог DIR1 с содержанием в DIR2.

Вывод будет немного многословным, но он покажет вам, какие файлы / каталоги различаются. Файлы / каталоги, присутствующие в, DIR2а не в, DIR1будут начинаться со словом deleting.

В некоторых ситуациях ответ @ slartibartfast может быть более уместным, хотя вам нужно убрать -type dопцию, чтобы включить список файлов, не входящих в каталог. rsyncбудет быстрее, если у вас есть значительное количество файлов / каталогов для сравнения.

созерцаемое
источник
Отличный ответ. В выводе rsync трудно заметить deleting...текст, но это, вероятно, один из лучших способов сравнения файлов при сохранении скорости. Другие ответы здесь быстрее, когда различие файлов не требуется ... как в примере с OP, но мне действительно нравится этот.
Джоэл Меллон
Это то, что я был после. У меня было несколько файлов разных размеров в огромной паре деревьев каталогов, и я хотел знать, какие из них. Это достигло этой цели в считанные секунды.
СУПРЯМИ
Может быть, это хорошая идея, чтобы запустить его с пользователем, который имеет доступ только для чтения. Как sudo -u nobody rsync -nav --delete d1 d2при условии, что флаги для «других» позволяют читать.
user1182474
При запуске этого решения я получил «создание списка файлов ... выполнено \ n отправлено X байт, получено Y байт, Z байт / с, общий размер равен A, ускорение равно B» (где я заменил XYZAB на числа). Значит ли это, что все было идентично? Так как это не упомянуло ничего более конкретного? Заранее спасибо
Скотт Х
Чтобы ответить на мой собственный вопрос, я экспериментировал с добавлением разных файлов к каждому, и кажется, что никакие конкретные файлы / каталоги, упомянутые в выходных данных, не означают, что они все одинаковы.
Скотт Х
18

Аналогичен ответу ls, но если вы установите дерево, вы можете

tree dir1 > out1
tree dir2 > out2
diff out1 out2
цифра
источник
7
Или чтобы избежать tmpfiles,diff <( tree dir1 ) <( tree dir2 )
Джоэл Меллон
1
Я рекомендую запустить дерево с iфлагом, который не печатает линии дерева ( tree -i dir1и т. Д.). Если структура каталогов отличается в одном месте, другие совпадающие файлы могут иметь больше или меньше |символов в выводе дерева, и diff поймает эти строки, даже если пути к файлам идентичны.
Askewchan
2
diff <(tree -i dir1) <(tree -i dir2) - лучший ответ. Я испытываю желание понизить все ответы, которые предлагают diff или rsync, так как вопрос явно говорит НЕ читать содержимое файла. ПРИМЕЧАНИЕ. Предложение использовать две трубы требует осторожного использования пробелов между скобками, точно следуйте примеру. Например, для сравнения двух томов 20G после резервного копирования древовидный ответ занял около 5 секунд. Остальные заняли более 20 минут.
Джейсон Морган
3

Я просто искал решение этой проблемы. Решение, которое мне понравилось больше всего, было:

comm <(ls DIR1) <(ls DIR2)

Это дает вам 3 столбца: 1 - файлы только в DIR1, 2 - файлы только в DIR2, 3 - файлы только в DIR3. Для более подробной информации смотрите этот пост в блоге.

kyrisu
источник
Где DIR3указано? Все, что я вижу, это DIR1и DIR2.
Майкл Дорст
Я попробовал это, и (от того, что я могу сказать) выход был: все файлы только DIR1в столбце 1 , все файлы только в DIR2в колонке 2 , и все файлы , разделяемые и в колонке 3 . Это полезно, но знаете ли вы, как можно удалить столбец 3 и оставить только различия? У меня много файлов для сортировки, и большинство из них идентичны. Мне не нужно видеть, что то же самое.
Майкл Дорст
1
Кроме того, я обнаружил, что comm <(ls DIR1) <(ls DIR2)не работает рекурсивно. Для этого я использовал comm <(ls -R1 DIR1) <(ls -R1 DIR2). ls -Rрекурсивно сканирует каталоги и ls -1(обратите внимание, что это единица , а не буква L ) lsвыдает только одно имя файла на строку.
Майкл Дорст
@ Майкл: comm -3(см. man comm).
Заз
2
ls > dir1.txt

ls > dir2.txt

Затем просто рассмотрите два списка.

MDMarra
источник
Похоже, что ОП хочет иерархию путей. Это будет отличать все файлы в текущем каталоге. Это спорный вопрос, но возможно, что он просто хочет каталогов; он может захотеть имена файлов, а не содержимое файлов.
интуитивно
@intuited - ты прав. Я неправильно понял
MDMarra
2

Это оптимальное решение

diff --brief -r dir1 dir2

Переключатель --brief сообщает только о том, отличаются ли файлы, а не о деталях различия.

jkshah
источник
1
У ОП уже есть -qвопрос, который является псевдонимом для --brief. Этот ответ не предоставляет никакой новой информации.
Майкл Дорст
1
OP не хочет сравнения содержимого файла. But it's really slow because it's comparing files too.
Джоэл Меллон
1

используйте "diff -qr", чтобы получить разные файлы, а затем отфильтруйте сравнение файлов с помощью grep, чтобы получить только имена файлов, которые находятся только в одном из каталогов.

diff -qr dir1 dir2 | grep -v "Files.*differ" 
анонимное
источник
1

Это сработало для моей конкретной необходимости найти отсутствующие файлы в деревьях, которые, как ожидается, будут совпадать.

diff <( cd dir1; find * |sort ) <(cd dir2; find * | sort)
amhest
источник
-3

Я думаю, что только rsync удобен. Почему?

diff полезен только для структур, хранящих файлы и каталоги. Diff не дает адекватных кодов выхода, когда мы используем символические ссылки. В этой ситуации diff может вернуть 2 кода выхода, даже если src и dst идентичны (время, размеры, имена, временные метки, указывающие программные ссылки и т. Д.).

dir, файловая система не гарантирует порядок файлов, даже если содержимое каталогов в src и dst идентично. Возможно, вам следует отфильтровать вывод ls, отсортировав его. Но чистый ls отображает только имена узлов.

может быть, сценарий, включающий diff, cmp, test -X для типов узлов, будет полезен, но помните о перегрузке, создаваемой многими запусками test / cmp. Сценарий будет очень медленным.

Как обычно, если вы хотите получить простую информацию «dirs is / not same», вы должны использовать rsync с опцией -n (dry). Если вы хотите найти отличия, используйте команду diff.

Znik
источник
Хотелось бы узнать почему минусы?
Зник