Как я могу заставить 'diff -X' игнорировать определенные пути, а не имена файлов?

29

Выполнение: diff -r -X <ignore-list> <src-dir> <dest-dir>

кажется, не делает diffигнорировать записи, <ignore-list>если они имеют форму <dir>/<file>.

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

Похоже, в справочной странице не так много информации о синтаксисе шаблонов diff. Из того, что я могу сказать, это просто базовое имя файла, который рассматривается diff (см. Http://forums.gentoo.org/viewtopic-t-889788-start-0.html, если вам интересно).

ясень
источник
человек, diff«s --excludeвариант так хреново ...
Elouan Keryell-Даже

Ответы:

30

Списки каталогов должны работать; например, вот что я использовал в сценарии (при условии, что GNU diff),

diff -r \
   --exclude="*~" \
   --exclude=".svn" \
   --exclude=".git" \
   --exclude="*.zip*" \
   --exclude="*.gz" \
   --exclude="*.tar" \
   ...etc

... который игнорирует содержимое .svnи .gitdirs, но также и отдельные файлы с именем *.zip/ *.gz/ etc.

Редактировать: чтобы отфильтровать пути формы, dir_a/file1но все же diffфайлы с одинаковым базовым именем, например, dir_b/file1или dir_a/b/file1, необходимо создать список файлов diff(например, с помощью find) и файл для сравнения, полученный из этих путей; например, учитывая

$ find ONE TWO -type f -print 
ONE/a/1.txt
ONE/a/2.txt
ONE/a/b/2.txt
TWO/a/1.txt
TWO/a/2.txt
TWO/a/b/2.txt

вы генерируете список файлов для сравнения, исключая, например, */a/2.txtно сравнивая другие файлы с именами 2.txt. Просто "найдите" все файлы, кроме ONE/a/2.txt(здесь также можно использовать регулярное выражение, например .*/a/2.txt)

$ find ONE -type f \( ! -regex 'ONE/a/2.txt' \) \
    -exec bash -c 'diff -q "${1}" "${2/ONE/TWO}"' - {} {} \;  

который фактически игнорирует ONE/a/2.txtTWO/a/2.txt), но сравнивает другие файлы с именем 2.txt:

diff -q ONE/a/1.txt TWO/a/1.txt
diff -q ONE/a/b/2.txt TWO/a/b/2.txt

Редактировать: Или, более весело с find(дополнительное удовольствие оставлено как упражнение для читателя), выберите файлы или каталоги для исключения, а затем diffвсе остальное:

$ find ONE \( -regex 'ONE/a/2.txt' -o -name b  -prune \)  \
    -o -type f -exec bash -c 'echo diff -q "${1}" "${2/ONE/TWO}"' - {} {} \

Приведенный выше пример исключает конкретный файл "{top} /a/2.txt", любой каталог с именем "b" и все остальное diff'd. (Вместо простого " -name b" вы также можете использовать " -regex '.*/b'" - обратите внимание, без трейлинга "/".)

Майкл
источник
2
Спасибо, но я думаю, что вы упускаете суть. Кажется, единственная поддержка - это когда вы используете 'base-name'. Это может быть имя каталога или файла. В любом случае, diff игнорирует то, что вы просили. Проблема возникает, когда вы используете пути. Например, я не могу заставить diff игнорировать / a / absolute / path / to / a / file или ./a/relative/path/to/a/file.
Пепел
2
diff --exclude = "/ this / specific / file / that / im / явно / умоляющий / you / to / ignore". Это не сработает.
Пепел
3
правильно, excludeшаблоны сопоставляются с базовым именем файла (согласно gnu.org/software/diffutils/manual/html_node/… ); пути не будут работать (как в foo/bar.txt). Для этого вам, вероятно, придется запустить findсписок имен файлов и определить путь к файлу для сравнения.
Майкл
обновленный ответ, чтобы включить пример, исключая пути к файлам из diff, вместо того, чтобы просто использоватьbasename
Майкл
Хорошо, я понимаю, что вы предлагаете, но, похоже, есть проблема. Мне нужно также рассмотреть каталоги, а не только файлы (то есть -type f). Теперь, хотя вы все еще можете удалять определенные файлы с помощью regexp find, если входные данные diffсодержат каталог, он будет проходить и сравнивать файлы в этом каталоге, и некоторые из этих файлов, возможно, придется игнорировать .... так что вы обратно на площадь 1.
Пепел
1

Чтобы исключить каталог directory/sub-directory, я использую

diff -r <src-dir> <dest-dir> | grep -v directory/sub-directory

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

Элуан Керилл-Эвен
источник
-2
$ diff -rq foo.orig foo | grep -vP 'ignore1/|exclude2/' | awk '{print $2}' | cut -d'/' -f2- | xargs -I{} diff -u foo.orig/{} foo/{}
Верн
источник
1
Хотя это может дать ответ на вопрос, было бы лучше, если бы вы могли объяснить, почему это так.
ДэвидПостилл