rsync сравнить каталоги?

63

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

ls -alRи diffздесь не вариант, поскольку в источнике есть жесткие ссылки, делающие каждую строку разной. (Конечно, я мог бы удалить этот столбец с помощью Perl.)

Крис
источник
Аналогично: serverfault.com/questions/62364/…
reinierpost

Ответы:

46

Вероятно, вам придется бежать что-то вроде rsync -avun --deleteв обоих направлениях.

Но чего вы на самом деле пытаетесь достичь?

Обновление :

rsync -avun --delete $TARGET $SOURCE |grep "^deleting " выдаст список файлов, которые не существуют в target-каталоге.

"grep delet", потому что каждая строка печатает: delet ing ..file ..

rsync -avun $SOURCE $TARGET выдаст вам список «разных» файлов (включая новые файлы).

Nils
источник
49

Чтобы добавить ответ Нильса (для всех, кто сталкивался с этим через Google), по умолчанию rsyncсравниваются только размеры файлов и время модификации, чтобы определить, есть ли различия. (Если они отличаются, это делает больше, но если они одинаковы, это останавливается там.)

Если вы хотите сравнить фактическое содержимое файла , даже для файлов, которые имеют одинаковый размер и время последнего изменения, добавьте флаг, -cчтобы сказать, rsyncчтобы сравнивать файлы, используя контрольную сумму.

rsync -avnc $SOURCE $TARGET

(Эта -uопция указывает rsync игнорировать файлы, которые новее, $TARGETчем те $SOURCE, которые вам, вероятно, не нужны, если вы сравниваете содержимое.)

user98393
источник
6
Если вы заботитесь только о том, чтобы данные были одинаковыми, вы можете добавить --no-group --no-owner --no-perms --no-timesили их комбинацию в зависимости от ваших потребностей.
flungo
1
@flungo, или просто используйте подмножество опций, подразумеваемых -aвместо -a, например,rsync -rlDcnv --delete $SOURCE $TARGET
maxschlepzig
Пожалуйста, добавьте --deleteв список только файлы, существующие в$TARGET
Том Хейл
25

Просто для тех, кто менее знаком с rsync:

rsync -rvnc --delete ${SOURCE}/ ${DEST}
  • -n: самое главное - ничего не менять;
  • -rc: сравнивайте только содержимое (иначе используйте -ac);
  • -v : список файлов)
  • --delete : ищите симметричную, а не однонаправленную разницу.
  • Наконец, /означает «заглянуть внутрь каталога и сравнить его содержимое с местом назначения».

Он напечатает обычный rsyncвывод,

  • с одним <filename> в строке для каждого "нового" файла в${SOURCE}
  • и одна строка «delete <filename>» для каждого «нового» файла в ${DEST}.

  • Он также может вывести несколько предупреждений, например, «пропустить нестандартный файл <имя файла>» для символических ссылок.

PS. Я знаю, что это ужасный PS - но он действительно был добавлен в спешке. Тем не менее, держу пари, что это может оказаться полезным.


PPS. В качестве альтернативы можно также сделать

find $SOURCE -type f -exec md5sum {} \; | tee source.md5
find $DEST   -type f -exec md5sum {} \; | tee dest.md5

Если имена файлов не содержат символов новой строки, мы можем отсортировать как *.md5файлы, так и diffих. (Однако это будет работать только для файлов; то есть пустой каталог с обеих сторон не будет обнаружен.)

ジ ョ ー ジ
источник
16

Удивительно, но ни один ответ через 6 лет не использует эту -iопцию или не дает хорошего результата, так что я пойду:

TLDR - просто покажи мне команды

rsync -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L             /'
rsync -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R             /'
rsync -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'

Понимание вывода

Вот пример вывода:

L             file-only-in-Left-dir
R             file-only-in-right-dir
X >f.st...... file-with-dif-size-and-time
X .f...p..... file-with-dif-perms

Обратите внимание на первый символ каждой строки:

  • L/ Rозначает, что файл / dir появляется только в Left или ight Rdir.
  • Xозначает , что с обеих сторон появляется файл , но это не то же самое (в этом случае следующие 11 символов дать вам больше информации. s, tи pпоказывают различия в ы Изе, т IME и р ermissions соответственно - для получения дополнительной информации попробуйте man rsyncи поиск --itemize-changes) ,

Дополнительные опции, которые вы можете использовать

Если вы также хотите сравнить владельца / группу / права доступа к файлам, добавьте опции -o/ -g/ -pсоответственно. В заключение отметим, что по умолчанию rsync считает два файла одинаковыми, если они имеют одинаковое имя, время и размер. Это очень быстро и в большинстве случаев более чем достаточно, но если вы хотите быть на 100%, добавьте -cтакже, чтобы сравнить содержимое файлов с тем же именем, временем и размером.

TLDR - просто дай мне сценарий, чтобы позвонить

Вот. Назови это так

diff-dirs Left_Dir Right_Dir [options]

Все опции, упомянутые выше в разделе «Дополнительные опции, которые вы можете использовать», также применимы и здесь.

#!/bin/bash
# Compare two directories using rsync and print the differences
# CAUTION: options MUST appear after the directories
#
# SYNTAX
#---------
# diff-dirs Left_Dir Right_Dir [options]
#
# EXAMPLE OF OUTPUT
#------------------
# L             file-only-in-Left-dir
# R             file-only-in-right-dir
# X >f.st...... file-with-dif-size-and-time
# X .f...p..... file-with-dif-perms
#
# L / R mean that the file/dir appears only at the `L`eft or `R`ight dir. 
#
# X     means that a file appears on both sides but is not the same (in which
#       case the next 11 characters give you more info. In most cases knowing
#       that s,t,T and p depict differences in Size, Time and Permissions 
#       is enough but `man rsync` has more info
#       (look at the --itemize-changes option)
#
# OPTIONS
#---------
# All options are passed to rsync. Here are the most useful for the purpose
# of directory comparisons:
#
# -c will force comparison of file contents (otherwise only
#    time & size is compared which is much faster)
#
# -p/-o/-g will force comparison of permissions/owner/group

if [[ -z $2 ]] ; then
    echo "USAGE: $0 dir1 dir2 [optional rsync arguments]"
    exit 1
fi

set -e

LEFT_DIR=$1; shift
RIGHT_DIR=$1; shift
OPTIONS="$*"

# Files that don't exist in Right_Dir
rsync $OPTIONS -rin --ignore-existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^[^ ]* /L             /'
# Files that don't exist in Left_Dir
rsync $OPTIONS -rin --ignore-existing "$RIGHT_DIR"/ "$LEFT_DIR"/|sed -e 's/^[^ ]* /R             /'
# Files that exist in both dirs but have differences
rsync $OPTIONS -rin --existing "$LEFT_DIR"/ "$RIGHT_DIR"/|sed -e 's/^/X /'

Как это работает?

Мы называем rsync следующим образом:

rsync -rin ...

Мы используем -i( --itemize-changes), чтобы сообщить rsync о выводе одной строки вывода для каждого файла, который содержит информацию о любых различиях между двумя каталогами. Нам нужно -nподавить нормальное поведение rsync (то есть попытаться синхронизировать два каталога путем копирования / удаления файлов). нам также нужно -rработать рекурсивно для всех файлов / подкаталогов.

Мы вызываем rsync три раза:

1-й вызов : распечатать файлы, которые не существуют в Dir_B. Нам нужно использовать, --ignore-existingчтобы игнорировать файлы, которые существуют с обеих сторон.

rsync -rin --ignore-existing $DIR_A/ $DIR_B/

2-й вызов : точно так же, как и раньше, но мы меняем порядок DIR_A / DIR_B.

3-й вызов : наконец, мы используем --existingтолько для проверки файлов, которые появляются в обоих каталогах.

rsync -rin --existing $DIR_A/ $DIR_B/
ndemou
источник
Не знаю о других, но я использую ваш сценарий. Отличная работа! спасибо
Маринайо
Спасибо вам большое! Мне нужны были некоторые твики, поделюсь ими ниже на случай, если кто-то ищет что-то подобное. Во-первых, я хотел запустить удаленный rsync от имени пользователя sudo, для этого я добавил --rsync-path="sudo rsync"каждую команду rsync. Во-вторых, я хотел сравнить локальный каталог с удаленным каталогом. Я добавил, --rsh "ssh -p1234"потому что в моем случае SSH работает через порт 1234. Затем я назвал скрипт как diff-dirs user@111.11.1.1:/mnt/Vol1/dir1/ /localMnt/dir1 -c.
sen4ik
7

Из вашего вопроса я понимаю, что вы не хотите использовать diff для ls , но вы также можете использовать diff рекурсивно для каталогов:

diff -rq DIR1 DIR2
фургон
источник
2

Мне понадобилось несколько попыток, чтобы заставить это работать. Ответ Нильса требует, чтобы он $TARGETзаканчивался буксировкой /, как объяснено ジ ョ ー ジ.

Вот версия, которая явно добавляет трейлинг /:

rsync -avun --delete ${TARGET}/ ${SOURCE}  | sed -ne 's/^deleting *//p'

Это дает список файлов, которые существуют под ${SOURCE}каталогом, но не ниже ${TARGET}каталога.

Я использую sedздесь, чтобы удалить ведущие deletingиз выходных строк, и для печати только эти строки.

Я не использую эту rsyncопцию, -cпотому что сравнение содержимого файла будет намного медленнее для моих вариантов использования, и сравнение только размеров файлов и времени модификации также кажется достаточным в этих случаях. У меня нет причин подозревать, что мои компьютеры страдают от проблем с перекосом часов или что что-то злонамеренно изменило метки времени. Кроме того, результат -cне может изменить решение об удалении файла, только решение об обновлении или сохранении файла.

Я также использую -uи -a(а не -r), чтобы впоследствии я мог повторно использовать командную строку и изменить ее для копирования выбранных каталогов и файлов из ${SOURCE}в ${TARGET}, например, так:

rsync -avu ${SOURCE}/{dirA,dirB,fileX} ${TARGET}   # copy some files
Orafu
источник
0

У меня есть другая идея сделать это:

rsync -rn --out-format=FILEDETAIL::%n  $TARGET $SOURCE  | grep "^FILEDETAIL"

Вы можете сопоставить «FILEDETAIL ::» с выводом команды. Также вы можете изменить строку "FILEDETAIL ::". «% N» - это имя файла.

-r Это говорит rsync о рекурсивном копировании каталогов.

-n Это заставляет rsync выполнить пробный запуск, который не вносит никаких изменений.

Чжао Тони
источник