Рекурсивно порівнюйте два каталоги з diff -r без виводу на зламані посилання


38

Я використовую diff -r a bдля рекурсивного порівняння каталогів a і b . Хоча часто трапляється, що існують деякі зламані зв’язки (однакові розбиті посилання як в каталогах a, так і в b і вказують на ті самі, неіснуючі цілі).

diff, то виводить повідомлення про помилки для цих випадків і виходить із ненульовим кодом виходу, однак я б хотів, щоб воно мовчало, і виходило з 0, оскільки каталоги однакові в моїй книзі.

Як я можу це зробити?


Ви все ще хочете порівнювати символьні посилання (і ідентифіковані як еквівалентні, але зламані), або допустимо ігнорувати всі символьні посилання, роблячи це різницею?
ire_and_curses

порівнюють і ідентифікують як еквівалент, мені байдуже, якщо вони порушені Я просто намагаюся переконатися, що мій rsync працював.
Маркус Юній Брут

Відповіді:


24

Для версії 3.3 або пізнішої версії diffслід скористатися --no-dereferenceпараметром, описаним у відповіді Піта Харлана .

На жаль, старіші версії diff не підтримують ігнорування символьних посилань :

Деякі файли не є ні каталогами, ні звичайними файлами: це незвичайні файли, такі як символьні посилання, спеціальні файли пристрою, названі труби та сокети. В даний час diffобробляє символічні посилання, як звичайні файли; він розглядає інші спеціальні файли, як звичайні файли, якщо вони вказані на верхньому рівні, але просто повідомляє про їх наявність при порівнянні каталогів. Це означає, що patchне можна представляти зміни таких файлів. Наприклад, якщо ви змінюєте, на який файл вказує символічне посилання, diffвиводить різницю між двома файлами замість зміни на символічне посилання.

diffслід необов'язково повідомляти про зміни в спеціальних файлах спеціально, і їх patchслід розширити, щоб зрозуміти ці розширення.

Якщо все, що вам потрібно, це перевірити rsync (і, мабуть, виправити те, чого немає), тоді ви можете просто запустити команду rsync вдруге. Якщо ви цього не хочете, можливо, буде достатньо перевірити підбиття підсумків каталогу .

Якщо ви дійсно хочете зробити це за допомогою diff, ви можете скористатися findдля пропуску символьних посилань та запуску розрізних файлів для кожного файлу окремо. Введіть ваші каталоги a і b в якості аргументів:

#!/bin/bash
# Skip files in $1 which are symlinks
for f in `find $1/* ! -type l`
do
    # Suppress details of differences
    diff -rq $f $2/${f##*/}
done

або як однолінійний:

for f in `find a/* ! -type l`;do diff -rq $f b/${f##*/};done

Це дозволить визначити файли, які відрізняються за змістом, або файли, що знаходяться в а, але не в b .

Зауважте, що:

  • оскільки ми повністю пропускаємо посилання, це не помітить, якщо імена символьних посилань відсутні в b . Якщо вам цього потрібно, вам знадобиться другий пропуск для виявлення всіх символьних посилань, а потім чітко перевірити їх існування в b .
  • Додаткові файли в b не будуть ідентифіковані, оскільки список побудований із вмісту a . Це, мабуть, не є проблемою для вашого rsyncсценарію.

Запропонований сценарій не працює рекурсивно для будь-яких каталогів, що знаходяться в каталозі 'a' (шляхи, створені для 'b' за допомогою b / $ {f ## *}, невірні).
Маркус Юній Брут

@MarcusJuniusBrutus - Так, ти маєш рацію. Я думаю, що рішення - видалити #, наприклад for f in знайти / *! -типу l ;do echo $f b/${f#*/};done. Я зараз не встигаю перевірити це. Повідомте мене, якщо це працює.
ire_and_curses

Це є , проте краще все - таки псує шляхів файлів у багатьох випадках. Сценарій (з # видалено), як видається, потрібно викликати з каталогу безпосередньо над "a", щоб працювати.
Маркус Юній Брут

Ця відповідь застаріла при використанні GNU diff 3.3 (див. Повідомлення нижче)
Bernd Gloss

У вищезазначеного сценарію є декілька проблем, пов’язаних із тим, що спочатку знайти всі імена файлів та подати їх до розширеного командного рядка. (1) З цього часу вона працюватиме лише з невеликими колекціями файлів. (2) Будь-яке ім'я файлу зі спеціальним символом (навіть пробіл) не оброблятиметься. (3) Завжди використовуйте $(xxx)замість заднього плану. Симетрія задньої панелі робить їх менш читабельними та запобігає гніздженню. Що стосується 1 і 2 см stackoverflow.com/questions/11366184 / ...
Стефан Горічон

19

Оскільки версія 3.3 GNU diffпідтримує не перенаправлення символьних посилань, але потім порівнює шляхи, на які вони вказують.

Встановіть GNU diffutils> = 3.3 та скористайтеся --no-dereferenceопцією; для цього немає короткого варіанту.

Діагностика буде беззвучною, якщо вона дорівнює або:

Символічні зв’язки /tmp/noderef/a/symlinkі /tmp/noderef/b/symlinkвідрізняються


Тепер якби це показувало змістові зміни, ніби символьне посилання було звичайним файлом ...: - /
lindes

6

Ви можете використовувати новішу версію diff

В diffGNU diffutils3.3 включена --no-dereferenceопція, яка дозволяє порівнювати самі посилання, а не їх цілі. Він повідомляє, якщо вони різняться, тихий, якщо вони згодні, і не байдуже, чи порушені вони.

Я не знаю, коли опція була додана; його немає в 2.8.1.


Я можу підтвердити, чи не існує в diff (GNU diffutils) 3.2 також
Elder Geek
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.