Solo he realizado pruebas de funcionalidad limitadas, así que tenga cuidado con este comando (--dry-run):
rsync -avPr --ignore-existing --remove-source-files src/ dest
Tenga en cuenta el final / ya que esto se repetirá en src en lugar de copiar src en sí mismo, esto debería mantener sus rutas existentes.
Al usar el indicador --ignore-existing en combinación con el indicador --remove-source-files, eliminará solo los archivos de src que están sincronizados de src a dest, es decir, archivos que no existían previamente en dest solamente.
Para eliminar archivos no sincronizados, es decir, aquellos que ya existían en dest/ como en src/, puede usar:
for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done
o
find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;
si los nombres de los archivos pudieran contener espacios en blanco/líneas nuevas/… Con respecto al comentario de Gilles sobre los caracteres especiales, eso es ciertamente algo a tener en cuenta y hay muchas soluciones, la más simple sería pasar un -i a rm que aparecerá antes de la eliminación. Sin embargo, siempre que se proporcione src/, o su ruta principal, para encontrar, la ruta completamente calificada debería dar como resultado que todos los nombres de archivo se manejen correctamente mediante los comandos diff y rm sin comillas.
unísono es la herramienta que estás buscando. Pruebe unison-gtk si prefiere una interfaz gráfica de usuario. Pero no creo que elimine archivos similares:al unísono intente que ambos directorios sean idénticos. Sin embargo, fácilmente 1) identificará qué archivos se van a copiar; 2) cuáles necesitan fusión manual.
El siguiente script debería hacer las cosas razonablemente. Mueve archivos desde el origen hasta el destino, nunca sobrescribe un archivo y crea directorios según sea necesario. Los archivos de origen que tienen un archivo diferente correspondiente en el destino se dejan solos, al igual que los archivos que no son archivos o directorios regulares (por ejemplo, enlaces simbólicos). Los archivos que quedan en la fuente son aquellos para los que hay un conflicto. Cuidado, no lo he probado en absoluto.
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
' {} \;
Otro enfoque sería hacer una unión de montaje de un directorio encima del otro, por ejemplo, con funionfs o unionfs-fuse.