web-dev-qa-db-fra.com

comparer 2 répertoires et copier les différences dans un 3e répertoire

Sous Ubuntu 12.04, je veux comparer 2 répertoires, par exemple dossier1/et dossier2/et copier tous les fichiers différents de dossier3 /. Il existe également des fichiers imbriqués, donc les sous-répertoires correspondants doivent également être copiés

Y a-t-il une seule commande qui pourrait m'aider? Je peux obtenir la liste complète des fichiers modifiés en cours d'exécution:

rsync -rcnC --out-format="%f" folder1/ folder2/

Mais rsync ne semble pas avoir la possibilité "d'exporter" ces fichiers sur un répertoire cible différent. Puis-je diriger la liste vers cp ou un autre programme, afin que les fichiers soient copiés, tandis que les répertoires sont également créés? Par exemple, j'ai essayé

rsync -rcnC --out-format="%f" folder1/ folder2/ | xargs cp -t folder3/

mais cela ne préserverait pas aussi les répertoires, cela copierait simplement tous les fichiers à l'intérieur du dossier3 /

32
periklis

Utilisez --compare-dest.

Depuis la page de manuel:

--compare-dest = DIR - Cette option indique à rsync d'utiliser DIR sur la machine de destination comme hiérarchie supplémentaire pour comparer les fichiers de destination avec les transferts (si les fichiers sont manquants dans le répertoire de destination). Si un fichier trouvé dans DIR est identique au fichier de l'expéditeur, le fichier NE sera PAS transféré vers le répertoire de destination. Ceci est utile pour créer une sauvegarde clairsemée de fichiers qui ont changé par rapport à une sauvegarde antérieure.

vérifiez d'abord votre syntaxe avec --dry-run

rsync -aHxv --progress --dry-run --compare-dest=folder2/ folder1/ folder3/

Ensuite, une fois que vous êtes satisfait de la sortie:

rsync -aHxv --progress  --compare-dest=folder2/ folder1/ folder3/

this link a une bonne explication de la portée --compare-dest.

38
smithian

Ce petit script devrait fonctionner:

folder1="firsts_folder/"
folder2="second_folder/"
folder3="target_folder"
for x in `rsync -rcnC --out-format="%n"  $folder1 $folder2`
    do
        if [ -d "$folder1/$x" ]; then
            mkdir -p "$folder3/$x"
        else
            cp -frv $folder1/$x $folder3/$x
        fi
done

Mais je pense également que l'analyse de la sortie de diff -qr serait une meilleure solution car elle vous donne systématiquement le chemin et le nom de chaque fichier.

MODIFIER

Ce serait une commande, votre commande légèrement modifiée. Mais cela créera folder1 sous le folder3. Et cela ne fonctionne pas avec les chemins d'accès complets, mais le script ci-dessus ne fonctionne pas non plus avec les chemins d'accès complets.

rsync -rcnC --out-format="\"%f\"" folder1/ folder2/ | xargs cp --parents -rfvt folder3/

J'ai utilisé \" in rsync pour le faire fonctionner avec des fichiers et des répertoires contenant des espaces. Testé sur Ubuntu 10.04. J'espère que cela aide.

3
rsync -rcnC --out-format="%f" . ../folder2/ |xargs cp --parents -rt ../folder3/

C'est la forme la plus simple que j'ai pu trouver, si vous êtes d'abord prêt à descendre dans folder1 avant d'émettre la commande.

Il s'agit de l'option plus lente, mais je pense qu'elle répond à vos exigences et pourrait être exécutée à l'aide de noms de répertoire non relatifs:

rsync -rcnC --out-format="%n" folder1/ folder2/ |grep -vP "/$" |xargs -I{} rsync -R folder1/./{} folder3/

J'ai laissé seule votre commande rsync d'origine, car vous avez dit qu'elle vous donnait la bonne liste de fichiers (et mes fichiers de test sont évidemment différents des vôtres, donc je ne pouvais pas dire avec certitude que j'obtiendrais le liste de fichiers correcte si je me suis trompé).

grep est là pour supprimer les noms de répertoire de la sortie de rsync.

La sortie de grep est ensuite redirigée vers un autre rsync à l'aide de xargs. Dans le param folder1/./{} l'extra ./ est utilisé pour dire à rsync de créer les répertoires relatifs commençant par ./{}, ignorant folder1/. En d'autres termes, cela évite de créer folder3/folder1/.

Je n'ai pu tester cela que sur CentOS 6.4, mais AFAIK cela devrait fonctionner de la même manière dans Ubuntu 12.04.

EDIT: Je dois noter que la réponse de smithian est sans aucun doute meilleure, mais je voulais essayer de le faire avec votre commande rsync d'origine avec tact car elle vous fournissait la sortie souhaitée.

2
s.co.tt