rsync compare les annuaires?

63

Est-il possible de comparer deux répertoires avec rsync et d'imprimer uniquement les différences? Il existe une option d'analyse à sec, mais lorsque j'augmente la verbosité à un certain niveau, chaque fichier comparé est affiché.

ls -alRet diffn’est pas une option ici, car il y a des liens durs dans la source rendant chaque ligne différente. (Bien sûr, je pourrais supprimer cette colonne avec perl.)

chris
la source
Similaire: serverfault.com/questions/62364/…
reinierpost

Réponses:

46

Vous devrez probablement exécuter quelque chose comme rsync -avun --deletedans les deux sens.

Mais qu'essayez-vous réellement d'accomplir?

Mise à jour :

rsync -avun --delete $TARGET $SOURCE |grep "^deleting " vous donnera une liste de fichiers qui n'existent pas dans le répertoire cible.

"grep delet" car chaque ligne s'imprime: supprime ing ..file ..

rsync -avun $SOURCE $TARGET vous donnera une liste de "différents" fichiers (y compris les nouveaux fichiers).

Nils
la source
49

Pour ajouter à la réponse de Nils (pour toute personne rencontrant cela via Google), par défaut, rsynccompare uniquement la taille des fichiers et les temps de modification pour indiquer s'il existe des différences. (Si celles-ci sont différentes, cela en fait plus, mais si elles sont identiques, cela s'arrête là.)

Si vous souhaitez comparer le contenu réel d'un fichier , même pour des fichiers ayant la même taille et la même heure de dernière modification, ajoutez l'indicateur -cpermettant rsyncde comparer les fichiers à l'aide d'une somme de contrôle.

rsync -avnc $SOURCE $TARGET

(L' -uoption indique à rsync d'ignorer les fichiers qui sont plus récents dans $TARGETque sur $SOURCE, que vous ne voulez probablement pas si vous comparez le contenu.)

utilisateur98393
la source
6
Si vous souhaitez uniquement que les données soient les mêmes, vous voudrez peut-être en ajouter --no-group --no-owner --no-perms --no-timesou une combinaison de celles-ci en fonction de vos besoins.
flungo
1
@flungo, ou utilisez simplement un sous-ensemble des options suggérées par à la -aplace de -a, par exemplersync -rlDcnv --delete $SOURCE $TARGET
maxschlepzig
S'il vous plaît ajouter --deleteà la liste des fichiers n'existant que dans$TARGET
Tom Hale
25

Juste pour ceux qui sont moins familiers avec rsync:

rsync -rvnc --delete ${SOURCE}/ ${DEST}
  • -n: Bit le plus important - ne pas changer quoi que ce soit;
  • -rc: comparer uniquement le contenu (sinon utiliser -ac);
  • -v : liste les fichiers)
  • --delete : recherchez une différence symétrique et non unidirectionnelle.
  • Enfin, /signifie "regarder à l'intérieur du répertoire et comparer son contenu à la destination".

Il imprimera une rsyncsortie habituelle ,

  • avec un <nom de fichier> sur une ligne pour chaque "nouveau" fichier dans${SOURCE}
  • et une ligne "suppression de <nom de fichier>" pour chaque "nouveau" fichier dans ${DEST}.

  • Il peut également imprimer quelques avertissements, tels que "ignorer le fichier non régulier <nom_fichier>" pour les liens symboliques.

PS Je sais que c'est un PS terrible - mais il a en effet été ajouté dans l'urgence. Néanmoins, je parie que cela pourrait être utile.


PPS. Alternativement, on pourrait aussi faire

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

Si les noms de fichiers ne contiennent pas de nouvelles lignes, nous pouvons alors trier les deux *.md5fichiers et diffles. (Cela ne fonctionnera que pour les fichiers, c’est-à-dire qu’un répertoire vide de chaque côté ne sera pas détecté.)

ョ ー ジ
la source
16

Étonnamment, pas de réponse dans 6 ans utilise l' -ioption ou donne une belle sortie alors je vais aller:

TLDR - Montre-moi juste les commandes

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 /'

Comprendre le résultat

Voici un exemple de la sortie:

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

Notez le premier caractère de chaque ligne:

  • L/ Rsignifie que le fichier / répertoire apparaît uniquement dans les Lrépertoires eft ou Right.
  • Xsignifie que le fichier apparaît sur les deux côtés , mais ne sont pas les mêmes (dans ce cas , les 11 caractères suivants vous donnent plus d' informations. s, tet preprésentent les différences de s Ize, t emps et p ermissions respectivement - pour plus d' informations essayer man rsyncet rechercher --itemize-changes) .

Options supplémentaires que vous voudrez peut-être utiliser

Si vous souhaitez également comparer le propriétaire / groupe / autorisations des fichiers, ajoutez les options -o/ -g/ -prespectivement. Enfin, notez que par défaut, rsync considère que deux fichiers sont identiques s’ils ont le même nom, la même heure et la même taille. C'est extrêmement rapide et la plupart du temps plus que suffisant, mais si vous voulez être sûr -cà 100%, vous devez également comparer le contenu de fichiers ayant le même nom, la même heure et la même taille.

TLDR - Donnez-moi juste un script à appeler

C'est ici. Appelez ça comme ça

diff-dirs Left_Dir Right_Dir [options]

Toutes les options mentionnées ci-dessus dans la section "Options supplémentaires que vous pouvez utiliser" s'appliquent également ici.

#!/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 /'

Comment ça marche?

Nous appelons rsync comme ceci:

rsync -rin ...

Nous utilisons -i( --itemize-changes) pour indiquer à rsync d’imprimer une ligne de sortie pour chaque fichier contenant des informations sur les différences éventuelles entre les deux répertoires. Nous devons -nsupprimer le comportement normal de rsync (qui consiste à essayer de synchroniser les deux répertoires en copiant / supprimant des fichiers). nous devons également -rtravailler de manière récursive pour tous les fichiers / sous-répertoires.

Nous appelons rsync trois fois:

1er appel : imprimer des fichiers qui n'existent pas dans Dir_B. Nous devons utiliser --ignore-existingpour ignorer les fichiers qui existent des deux côtés.

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

2ème appel : exactement comme avant, mais nous échangeons l'ordre de DIR_A / DIR_B.

3ème appel : Enfin, nous utilisons --existinguniquement pour vérifier les fichiers qui apparaissent dans les deux répertoires.

rsync -rin --existing $DIR_A/ $DIR_B/
Ndemou
la source
Je ne sais pas pour les autres, mais j'utilise votre script. Bon travail! merci
Marinaio
Merci beaucoup! J'avais besoin de quelques ajustements, je les partagerai ci-dessous au cas où quelqu'un chercherait quelque chose de similaire. Premièrement, je voulais exécuter rsync à distance en tant qu’utilisateur sudo, j’ai ajouté --rsync-path="sudo rsync"à chaque commande rsync. Deuxièmement, je voulais comparer le répertoire local avec le répertoire distant. J'ai ajouté --rsh "ssh -p1234"parce que dans mon cas, SSH fonctionne sur le port 1234. Ensuite, j'ai appelé script comme diff-dirs [email protected]:/mnt/Vol1/dir1/ /localMnt/dir1 -c.
sen4ik
7

Je comprends de votre question que vous ne voulez pas utiliser diff sur ls , mais vous pouvez également utiliser diff de manière récursive sur les répertoires:

diff -rq DIR1 DIR2
Camion
la source
2

Il m'a fallu quelques essais pour que cela fonctionne. La réponse de Nils exige que $TARGETse termine par une fin /, comme expliqué par ョ ー.

Voici une version qui ajoute explicitement la fin /:

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

Cela donne la liste des fichiers qui se trouvent sous le ${SOURCE}répertoire mais pas sous le ${TARGET}répertoire.

J'utilise sedici pour supprimer le début deletingdes lignes de sortie et pour n'imprimer que ces lignes.

Je n'utilise pas cette rsyncoption -ccar la comparaison du contenu d'un fichier serait beaucoup plus lente pour mes cas d'utilisation, et comparer uniquement la taille du fichier et les temps de modification semble également suffisant dans ces cas. Je n'ai aucune raison de penser que mes ordinateurs souffrent de problèmes d'horloge ou que quelque chose a changé malicieusement l'horodatage. En outre, le résultat de -cne peut pas changer la décision de supprimer un fichier, mais uniquement la décision de mettre à jour ou de conserver un fichier.

J'utilise aussi -uet -a(plutôt que -r), pour pouvoir ultérieurement réutiliser la ligne de commande et la modifier pour copier les répertoires et fichiers sélectionnés de ${SOURCE}vers ${TARGET}, comme ceci:

rsync -avu ${SOURCE}/{dirA,dirB,fileX} ${TARGET}   # copy some files
Orafu
la source
0

J'ai une autre idée de faire ceci:

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

Vous pouvez faire correspondre "FILEDETAIL ::" au résultat de la commande. Vous pouvez également modifier la chaîne "FILEDETAIL ::". Le "% n" est le nom du fichier.

-r Ceci indique à rsync de copier les répertoires de manière récursive.

-n Ceci oblige rsync à effectuer un essai sans aucune modification.

zhao Tony
la source