diff для вывода только имен файлов

244

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

barfoon
источник

Ответы:

376

Со страницы руководства diff:

-q   Сообщайте только, отличаются ли файлы, а не детали различий.
-r   При сравнении каталогов рекурсивно сравнивайте любые найденные подкаталоги.

Пример команды:

diff -qr dir1 dir2

Пример вывода (зависит от локали):

$ ls dir1 dir2
dir1:
same-file  different  only-1

dir2:
same-file  different  only-2
$ diff -qr dir1 dir2
Files dir1/different and dir2/different differ
Only in dir1: only-1
Only in dir2: only-2
Джон Кугельман
источник
Спасибо - diffсправочная страница в CentOS 7 описывается -qкак «отчет, только если файлы различаются», что менее понятно, чем то, что вы написали.
глава
2
При этом сравнивается фактическое содержимое файлов, что часто является тем, что нужно, однако ответ rsync дает возможность просматривать только имена и размеры файлов, а не содержимое; это иногда желательно.
Steveb
Работает и на macOS.
Мариус Сутье
Также может включать -x PATTERNв команду исключение определенных подкаталогов. Например, diff -qr repo1 repo2 -x ".git" сравнивает две директории, но исключает пути к файлам с «.git» в них.
ViFI
27

Вы также можете использовать rsync

rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out
boksiora
источник
6
--size-onlyпропустит файлы одинакового размера, но разного содержания, например old / version.txt "29a" new / version.txt "29b" . Вместо этого используйте: rsync -ric --dry-run old/ new/где аргумент "-i" позволяет получить список файлов напрямую черезrsync -ric --dry-run old/ new/ | cut -d" " -f 2
iolsmit
6
Это замечательно, если вы ищете только отсутствующие файлы (особенно между сетевыми папками), потому что они не сравнивают содержимое. Это помогло мне найти несколько файлов, которые не удалось перенести на новый NAS.
Превосходно
4
Обязательно включите косую черту для путей, указанных в командной строке rsync. Без них это не будет работать правильно, и rsync, скорее всего, просто перечислит все имена файлов!
Владимир Пантелеев
2
Что касается комментариев по поводу не проверки содержимого. Это иногда желательно, по крайней мере, в качестве первого прохода.
Steveb
13

Если вы хотите получить список файлов, которые находятся только в одном каталоге, а не их подкаталогах и только их именах файлов:

diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'

Если вы хотите рекурсивно перечислить все файлы и каталоги, которые отличаются своими полными путями:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'

Таким образом, вы можете применять различные команды ко всем файлам.

Например, я мог бы удалить все файлы и каталоги, которые находятся в dir1, но не в dir2:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}
Северная Дакота
источник
9

В моей системе Linux, чтобы получить только имена файлов

diff -q /dir1 /dir2|cut -f2 -d' '
gerardw
источник
7
Я не помещаю имена файлов с пробелами в мою систему Linux. ;)
gerardw
6
Я не хотел вменять тебе это ... ;-p Как намек на того, кто это делает ...
michuelnik
не работает для меня. Моя структура каталогов, как audit-0.0.234/audit-data-warehouse-0.0.234/ audit-0.0.235/audit-data-warehouse-0.0.235/
показано
diff -qrN /dir1 /dir2 | cut -f2 -d' 'у меня отлично работает!
Франческо
9

Подход запуска diff -qr old/ new/имеет один существенный недостаток: он может пропускать файлы во вновь создаваемых каталогах. Например, в приведенном ниже примере файла data/pages/playground/playground.txtнет в выводе, diff -qr old/ new/тогда как в каталоге data/pages/playground/(найдите для быстрого просмотра plays.txt в вашем браузере). Я также разместил следующее решение на Unix & Linux Stack Exchange , но скопирую его и здесь:

Чтобы создать список новых или измененных файлов программно, лучшее решение, которое я мог бы предложить, - это использовать rsync , sort и uniq :

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

Позвольте мне объяснить на этом примере: мы хотим сравнить два выпуска dokuwiki, чтобы увидеть, какие файлы были изменены, а какие были созданы заново.

Мы принести гудроны с Wget и извлечь их в каталогах old/и new/:

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

Запуск rsync в одну сторону может пропустить вновь созданные файлы, как показывает сравнение rsync и diff:

rsync -rcn --out-format="%n" old/ new/

дает следующий вывод:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

Запуск rsync только в одном направлении пропускает вновь созданные файлы, и наоборот, пропустит удаленные файлы, сравните вывод diff:

diff -qr old/ new/

дает следующий вывод:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

Выполнение rsync в обоих направлениях и сортировка вывода для удаления дубликатов показывает, что каталог data/pages/playground/и файл data/pages/playground/playground.txtбыли изначально пропущены:

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

дает следующий вывод:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync запускается с этими аргументами:

  • -r "вербоваться в каталоги",
  • -c также сравнивать файлы одинакового размера и только «пропускать по контрольной сумме, а не по времени и размеру»,
  • -n «выполнить пробный запуск без внесенных изменений», и
  • --out-format="%n" «выводить обновления, используя указанный ФОРМАТ», который здесь «% n» только для имени файла

Вывод (список файлов) rsyncв обоих направлениях объединяется и сортируется с использованием sort, а затем этот отсортированный список сокращается путем удаления всех дубликатов с помощьюuniq

iolsmit
источник
Не могли бы вы просто запустить его в обратном направлении ( diff new/ old/), чтобы увидеть, какие каталоги были удалены?
Жак
Выполнение diff -qr new/ old/приведенного выше примера с докувики tars дает тот же результат, что и diff -qr old/ new/- т.е. вы видите, что каталог новый / отсутствует, но нет файлов в нем
iolsmit
-4
rsync -rvc --delete --size-only --dry-run source dir target dir
Mayank
источник