Как сравнить файлы с одинаковыми именами в двух разных каталогах, используя скрипт оболочки - PullRequest
19 голосов
/ 23 сентября 2008

Прежде чем перейти к использованию SVN, я обычно управлял своим проектом, просто сохраняя каталог /develop/, редактируя и тестируя там файлы, затем перемещая их в каталог /main/. Когда я решил перейти на SVN, мне нужно было убедиться, что каталоги действительно синхронизированы.

Итак, как же написать сценарий оболочки [bash] для рекурсивного сравнения файлов с одинаковыми именами в двух разных каталогах?

Примечание. Названия каталогов, использованные выше, приведены только для примера. Я не рекомендую хранить ваш код на верхнем уровне:).

Ответы [ 6 ]

30 голосов
/ 23 сентября 2008

Команда diff имеет опцию -r для рекурсивного сравнения каталогов:

diff -r /develop /main
8 голосов
/ 23 сентября 2008
diff -rqu /develop /main

Это даст вам только краткую информацию об изменениях :)

Если вы хотите видеть только новые / отсутствующие файлы

diff -rqu /develop /main | grep "^Only

Если вы хотите получить их голыми:

diff -rqu /develop /main | sed -rn "/^Only/s/^Only in (.+?): /\1/p"
4 голосов
/ 23 сентября 2008

Различия, которые у меня есть, допускают рекурсивные различия:

diff -r main develop

Но с помощью сценария оболочки:

( cd main ; find . -type f -exec diff {} ../develop/{} ';' )
1 голос
/ 19 июля 2011

Вот пример моего (несколько грязного) скрипта, dircompare.sh , который будет:

  • сортировка файлов и каталогов в массивах в зависимости от того, в каком каталоге они находятся (или в обоих), за два рекурсивных прохода
  • Файлы, которые находятся в обоих каталогах, снова сортируются в двух массивах, в зависимости от того, определяет ли diff -q, различаются они или нет
  • для тех файлов, которые diff утверждают, равны, показать и сравнить метки времени

Надеюсь, что это может быть полезно - Ура!

EDIT2: ( На самом деле, он отлично работает с удаленными файлами - проблема была в том, что необработанный сигнал Ctrl-C во время операции сравнения между локальным и удаленным файлом, который может занять некоторое время; теперь скрипт обновляется с помощью ловушки для обработки что - однако, оставляя предыдущее редактирование ниже для справки ):

РЕДАКТИРОВАТЬ: ... за исключением того, что, кажется, сбой моего сервера для удаленного каталога SSH (который я пытался использовать более ~/.gvfs) ... Так что это не bash больше, но я думаю, что альтернатива заключается в использовании rsync, вот пример:

$ # get example revision 4527 as testdir1
$ svn co https://openbabel.svn.sf.net/svnroot/openbabel/openbabel/trunk/data@4527 testdir1

$ # get earlier example revision 2729 as testdir2
$ svn co https://openbabel.svn.sf.net/svnroot/openbabel/openbabel/trunk/data@2729 testdir2

$ # use rsync to generate a list 
$ rsync -ivr --times --cvs-exclude --dry-run testdir1/ testdir2/
sending incremental file list
.d..t...... ./
>f.st...... CMakeLists.txt
>f.st...... MACCS.txt
>f..t...... SMARTS_InteLigand.txt
...
>f.st...... atomtyp.txt
>f+++++++++ babel_povray3.inc
>f.st...... bin2hex.pl
>f.st...... bondtyp.h
>f..t...... bondtyp.txt
...

Обратите внимание:

  • Чтобы получить вышесказанное, вы не должны забывать завершающие косые черты / в конце имен каталогов в rsync
  • --dry-run - только моделировать, не обновлять / не передавать файлы
  • -r - зайти в каталоги
  • -v - многословно (но не относится к информации об изменениях файла)
  • --cvs-exclude - игнорировать .svn файлы
  • -i - "--itemize-changes: вывести сводку изменений для всех обновлений"

Вот краткая выдержка из man rsync, которая объясняет информацию, показанную -i (например, строки >f.st...... выше):

The  "%i"  escape  has a cryptic output that is 11 letters long.
The general format is like the string YXcstpoguax,  where  Y  is
replaced  by the type of update being done, X is replaced by the
file-type, and the other letters represent attributes  that  may
be output if they are being modified.

The update types that replace the Y are as follows:

o      A  < means that a file is being transferred to the remote
       host (sent).

o      A > means that a file is being transferred to  the  local
       host (received).

o      A  c  means that a local change/creation is occurring for
       the item (such as the creation  of  a  directory  or  the
       changing of a symlink, etc.).

...
The file-types that replace the X are: f for a file, a d  for  a
directory,  an  L for a symlink, a D for a device, and a S for a
special file (e.g. named sockets and fifos).

The other letters in the string above  are  the  actual  letters
that  will be output if the associated attribute for the item is
being updated or a "." for no change.  Three exceptions to  this
are:  (1)  a newly created item replaces each letter with a "+",
(2) an identical item replaces the dots with spaces, and (3)  an
....

Действительно, немного загадочно - но, по крайней мере, это показывает базовое сравнение каталогов по ssh. Ура!

1 голос
/ 23 сентября 2008

[Я где-то читал, что отвечать на ваши вопросы нормально, так что вот так :)]

Я попробовал это, и это сработало довольно хорошо

[/]$ cd /develop/
[/develop/]$ find | while read line; do diff -ruN "/main/$line" $line; done |less

Вы можете сравнить только определенные файлы (например, только файлы .php), отредактировав вышеуказанную строку как

[/]$ cd /develop/
[/develop/]$ find -name "*.php" | while read line; do diff -ruN "/main/$line" $line; done |less

Есть еще идеи?

0 голосов
/ 18 октября 2008

Классическим ответом (System V Unix) будет dircmp dir1 dir2, который представляет собой сценарий оболочки, который будет перечислять файлы, найденные либо в dir1, но не в dir2 или в dir2, но не в dir1 в начале (первая страница вывода с Команда pr, разбитая на страницы с заголовками), с последующим сравнением каждого общего файла с анализом (одни и те же, разные, каталоги были наиболее распространенными результатами).

Кажется, это происходит в процессе исчезновения - у меня есть независимое повторное воплощение, если оно вам нужно. Это не ракетостроение (cmp твой друг).

...