Скрипт оболочки для рекурсивного сравнения каталогов - PullRequest
3 голосов
/ 20 июля 2011

У меня есть резервная копия файлового сервера на внешнем жестком диске несколько месяцев назад для файлового сервера, который с тех пор вышел из строя.Большая часть данных была восстановлена ​​на временном файловом сервере, который использовался с тех пор, но есть некоторые несоответствия.

Я собираюсь смонтировать внешний и rsync его с текущими данными к нему, но сначала мне нужно установить файлы, которые были обновлены на более новой копии.

Я могу сделать diff -r-q / old / / new / чтобы получить это, я пытаюсь лучше разбираться в сценариях, поэтому я пытаюсь написать что-то, что переименует старый файл в filename.old, когда diff возвращает разницу.

Ответы [ 2 ]

4 голосов
/ 20 июля 2011

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

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

Files old/file and new/file differ

Поскольку ваш bash-скрипт будет переименовывать измененный файл из старого каталога, мы хотим извлечь old/file из этого вывода. Давайте начнем с отображения только таких строк, как Files...differ (как могут быть получены другие строки):

diff -rq old/ new/ | grep "^Files.*differ$"

Теперь вы получите только те строки, которые были показаны ранее. Следующим шагом является получение имени файла. Вы можете сделать это с помощью awk, добавив что-то вроде awk '{print $2}' в качестве другого канала, но если само имя файла содержит пробелы, awk разделит его на две отдельные строки. Вместо этого мы будем использовать sed:

diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'

Теперь это создаст список файлов, которые были изменены в старом каталоге. Используя простой цикл for, вы можете теперь переименовать каждый из файлов:

for old_file in `diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'`
do
   mv $old_file $old_file.old
done

И это все!

edit: на самом деле, это еще не все. Этот цикл все еще не работает на файлах с пробелами, поэтому давайте немного с этим справимся. for по умолчанию попытается создать список, разделенный пробелом. Давайте изменим это, чтобы использовать вместо этого новые строки:

OLD_IFS=$IFS
# The extra space after is crucial
IFS=\

for old_file in `diff -rq old/ new/ | grep "^Files.*differ$" | sed 's/^Files \(.*\) and .* differ$/\1/'`
do
   mv $old_file $old_file.old
done
IFS=$OLD_IFS

Это временно заменяет разделитель по умолчанию в bash ($IFS) на новую строку и возвращает его после завершения цикла, чтобы не разбивать пробел.

0 голосов
/ 20 июля 2011

Раньше была программа dircmp, скрывающаяся вокруг систем. Если у вас есть, используйте его.

Если у вас его нет и вы не можете его найти, у меня есть версия с небольшими расширениями, которую вы можете использовать (см. Мой профиль для получения контактной информации).

Пример вывода:

Files in ifxchkpath-4.12 only and in ifxchkpath-5.15 only

./Makefile                        ./absname.1
./program.mk                      ./absname.c
                                  ./chk.servers.sh
                                  ./chunklist.sh
                                  ./clnpath.c
                                  ./clnpath.h
                                  ./dirname.c
                                  ./enable.uids.sh
                                  ./errhelp.c
[...]
                                  ./lpt.pl
                                  ./makefile
                                  ./nvstrcpy.c
                                  ./realpath.c
                                  ./realpathtest.sh
                                  ./stderr.c
                                  ./stderr.h
                                  ./symlinks.tgz
                                  ./testids.mk
                                  ./test.linkpath.pl
                                  ./test.lpt.sh
                                  ./test.onsecurity.sh
                                  ./tokenise.c

Comparison of files in ifxchkpath-4.12 and ifxchkpath-5.15

directory           .
different           ./chk.ifxchkpath.sh
different           ./ifxchkpath.c
same                ./test.ifxchkpath.pl
...