Je n'ai effectué que des tests de fonctionnalité limités, veuillez donc être prudent avec cette commande (--dry-run):
rsync -avPr --ignore-existing --remove-source-files src/ dest
Veuillez noter le / final car cela se récursera dans src au lieu de copier src lui-même, cela devrait conserver vos chemins existants.
En utilisant l'indicateur --ignore-existing en combinaison avec l'indicateur --remove-source-files, vous supprimerez uniquement les fichiers de src qui sont synchronisés de src à dest, c'est-à-dire des fichiers qui n'existaient pas auparavant uniquement dans dest.
Pour supprimer les fichiers non synchronisés, c'est-à-dire ceux qui existaient déjà dans dest/ comme dans src/, vous pouvez utiliser :
for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done
ou
find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;
si les noms de fichiers pouvaient contenir des espaces/retours à la ligne/… Concernant le commentaire de Gilles concernant les caractères spéciaux, c'est certainement quelque chose dont il faut tenir compte et il existe de nombreuses solutions, la plus simple serait de passer un -i à rm qui demandera avant toute suppression. À condition que src/, ou son chemin parent, soit fourni pour trouver, cependant, le chemin complet devrait entraîner le traitement correct de tous les noms de fichiers par les commandes diff et rm sans guillemets.
unisson est l'outil que vous recherchez. Essayez unison-gtk si vous préférez une interface graphique. Mais je ne pense pas que cela supprimera les fichiers similaires:unison essaie d'avoir les deux répertoires identiques. Néanmoins, il sera facile 1) d'identifier les fichiers à copier; 2) lesquels nécessitent une fusion manuelle.
Le script suivant devrait faire les choses raisonnablement. Il déplace les fichiers de la source vers la destination, sans jamais écraser un fichier et en créant des répertoires si nécessaire. Les fichiers source qui ont un fichier différent correspondant dans la destination sont laissés seuls, de même que les fichiers qui ne sont pas des fichiers ou des répertoires normaux (par exemple, des liens symboliques). Les fichiers restants dans le source sont ceux pour lesquels il existe un conflit. Attention, je ne l'ai pas du tout testé.
cd src
find . -exec sh -c '
set -- "/path/to/dest/$0"
if [ -d "$0" ]; then # the source is a directory
if ! [ -e "$1" ]; then
mv -- "$0" "$1" # move whole directory in one go
fi
elif ! [ -e "$0" ]; then # the source doesn't exist after all
: # might happen if a whole directory was moved
elif ! [ -e "$1" ]; then # the destination doesn't exist
mv -- "$0" "$1"
elif [ -f "$1" ] && cmp -s -- "$0" "$1"; then # identical files
rm -- "$0"
fi
' {} \;
Une autre approche serait de faire un montage union un répertoire au-dessus de l'autre, par exemple avec funionfs ou unionfs-fuse.