compare 2 directorios y copie diferencias en un tercer directorio

32

Ejecutando ubuntu 12.04, quiero comparar 2 directorios, digamos carpeta1 / y carpeta2 / y copiar cualquier archivo que sea diferente a la carpeta3 /. También hay archivos anidados, por lo que también se deben copiar subdirectorios coincidentes

¿Hay un solo comando que me ayudaría? Puedo obtener la lista completa de archivos modificados en ejecución:

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

Pero rsync no parece tener la capacidad de "exportar" estos archivos en un directorio de destino diferente. ¿Puedo canalizar la lista a cp o algún otro programa, para que los archivos se copien, mientras que también se crean los directorios? Por ejemplo, intenté

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

pero eso no preservaría los directorios también, simplemente copiaría todos los archivos dentro de la carpeta3 /

periklis
fuente
Probablemente usaría alguna combinación de diff -qry awkpara construir la lista, entonces rsync...
ewwhite
¿Cómo usaría rsync con la lista?
periklis
Ejecuté un bucle for o utilicé la rsync --include-from=FILEopción.
ewwhite
(no seas perezoso ...) Pero la solución rsync a continuación es elegante.
ewwhite

Respuestas:

38

Utilice --compare-dest.

Desde la página del manual:

--compare-dest = DIR: esta opción indica a rsync que use DIR en la máquina de destino como una jerarquía adicional para comparar los archivos de destino con las transferencias (si faltan archivos en el directorio de destino). Si se encuentra un archivo en DIR que sea idéntico al archivo del remitente, el archivo NO se transferirá al directorio de destino. Esto es útil para crear una copia de seguridad dispersa de solo archivos que han cambiado desde una copia de seguridad anterior.

primero verifique su sintaxis con --dry-run

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

Luego, una vez que esté satisfecho con la salida:

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

este enlace tiene una buena explicación de --compare-dest scope.

smithian
fuente
1
Gracias por esto, no había entendido la explicación de la página de manual de este parámetro. Para cualquier persona interesada, lo hice conrsync -rcC --compare-dest=folder2/ folder1/ folder3/
periklis
nota rápida para usuarios de OsX. Tengo rsync version 3.1.1 protocol version 31en mi local y rsync no entiende ~/rutas para --compare-destparam.
Jevgeni Smirnov
44
Para mí, --compare-destrequería un camino absoluto.
palswim
No funcionó para mí con las opciones de autor o de OP. Es decir, genera el fonts/Makefile.inarchivo, que es idéntico en ambos folder2y en los folder1directorios.
Hi-Angel
3

Este pequeño script debería funcionar:

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

Pero también creo que analizar la salida de diff -qr sería una mejor solución porque te da la ruta y el nombre de cada archivo de manera consistente.

EDITAR

Este sería un comando, su comando ligeramente modificado. Pero creará folder1bajo el folder3. Y no funciona con rutas completas, pero tampoco el script anterior funciona con rutas completas.

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

He utilizado \"en rsynchacer que funcione con archivos y directorios que contiene espacios en blanco. Probado en Ubuntu 10.04. Espero eso ayude.

Laurentiu Roescu
fuente
gracias por esto, esperaba que existiera un solo comando
periklis
2
rsync -rcnC --out-format="%f" . ../folder2/ |xargs cp --parents -rt ../folder3/

Esa es la forma más simple que se me ocurre, si estás dispuesto a descender folder1antes de emitir el comando.

Esta es la opción más lenta , pero creo que cumple con sus requisitos, y podría ejecutarse utilizando nombres de directorio no relativos:

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

Dejé rsyncsolo tu comando original , porque dijiste que te estaba dando la lista de archivos correcta (y mis archivos de prueba son obviamente diferentes a los tuyos, por lo que no podría decir con certeza que obtendría la lista de archivos correcta si me equivocara con eso).

El grepestá allí para eliminar los nombres de directorio de la salida de rsync.

La salida de grepse canaliza a otra rsyncusando xargs. En el parámetro, folder1/./{}el extra ./se usa para indicarle a rsync que cree los directorios relativos comenzando por ./{}, ignorando folder1/. En otras palabras, evita crear folder3/folder1/.

Solo pude probar esto en CentOS 6.4, pero AFAIK debería funcionar igual en Ubuntu 12.04.

EDITAR: Debo señalar que la respuesta de Smith es indudablemente mejor, pero quería intentar hacerlo con tu rsynccomando original en el tacto ya que te estaba dando el resultado deseado.

s.co.tt
fuente