rsync compara directorios?

63

¿Es posible comparar dos directorios con rsync y solo imprimir las diferencias? Hay una opción de ejecución en seco, pero cuando aumento la verbosidad a un cierto nivel, se muestran todos los archivos comparados.

ls -alRy diffno es una opción aquí, ya que hay enlaces duros en la fuente que hacen que cada línea sea diferente. (Por supuesto, podría eliminar esta columna con perl).

Chris
fuente

Respuestas:

46

Probablemente tendrá que ejecutar algo parecido rsync -avun --deleteen ambas direcciones.

Pero, ¿qué estás tratando de lograr realmente?

Actualización :

rsync -avun --delete $TARGET $SOURCE |grep "^deleting " le dará una lista de archivos que no existen en el directorio de destino.

"grep delet" porque cada línea imprime: delet ing ..file ..

rsync -avun $SOURCE $TARGET le dará una lista de archivos "diferentes" (incluidos los archivos nuevos).

Nils
fuente
49

Para agregar a la respuesta de Nils (para cualquiera que se encuentre con esto a través de Google), por defecto rsyncsolo compara los tamaños de archivo y los tiempos de modificación para saber si hay alguna diferencia. (Si son diferentes, hace más, pero si son iguales, se detiene allí).

Si desea comparar el contenido real del archivo , incluso para archivos que tienen el mismo tamaño y la última hora de modificación, agregue la bandera -cpara indicar rsyncque compare los archivos usando una suma de verificación.

rsync -avnc $SOURCE $TARGET

(La -uopción le dice a rsync para ignorar los archivos que son nuevos en $TARGETque en $SOURCEque es probable que no desee si está comparando su contenido.)

usuario98393
fuente
66
Si solo le importa que los datos sean los mismos, es posible que desee agregar --no-group --no-owner --no-perms --no-timeso una combinación de estos según sus necesidades.
flungo
1
@flungo, o simplemente use un subconjunto de las opciones implícitas en -alugar de -a, por ejemplorsync -rlDcnv --delete $SOURCE $TARGET
maxschlepzig
Agregue --deletea la lista los archivos que solo existen en$TARGET
Tom Hale
25

Solo para aquellos menos familiarizados con rsync:

rsync -rvnc --delete ${SOURCE}/ ${DEST}
  • -n: bit más importante: no cambie nada;
  • -rc: compare solo los contenidos (de lo contrario, use -ac);
  • -v : enumerar los archivos)
  • --delete : busque una diferencia simétrica, no unidireccional.
  • Finalmente, /significa "mirar dentro del directorio y comparar su contenido con el destino".

Imprimirá una rsyncsalida habitual ,

  • con un <nombre de archivo> en una línea para cada archivo "nuevo" en${SOURCE}
  • y una línea de "eliminación de <nombre de archivo>" para cada archivo "nuevo" en ${DEST}.

  • También puede imprimir algunas advertencias, como "omitir el archivo no regular <nombre de archivo>" para enlaces simbólicos.

PD. Sé que es un PS terrible, pero de hecho se agregó rápidamente. Sin embargo, apuesto a que uno puede encontrar esto útil.


PPS Alternativamente, uno también podría hacer

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

Si los nombres de archivo no contienen nuevas líneas, podemos ordenar ambos *.md5archivos y diffellos. (Sin embargo, esto solo funcionará para archivos; es decir, no se detectará un directorio vacío a ambos lados).

ジ ョ ー ジ
fuente
16

Sorprendentemente, ninguna respuesta en 6 años usa la -iopción o da una buena salida, así que aquí voy:

TLDR - Solo muéstrame los comandos

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

Comprender la salida

Aquí hay un ejemplo de la salida:

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

Tenga en cuenta el primer carácter de cada línea:

  • L/ Rsignifica que el archivo / dir aparece solo en el directorio Left o Right.
  • Xsignifica que el archivo aparece en ambos lados, pero no es lo mismo (en cuyo caso los próximos 11 caracteres que dan más información. s, ty pmuestran diferencias en s ize, t iempo y p ermissions respectivamente - para obtener más información tratar man rsyncy buscar --itemize-changes) .

Opciones adicionales que puede desear usar

Si desea comparar también el propietario / grupo / permisos de los archivos, agregue las opciones -o/ -g/ -prespectivamente. Finalmente, tenga en cuenta que, de manera predeterminada, rsync considera que dos archivos son iguales si tienen el mismo nombre, hora y tamaño. Esto es extremadamente rápido y la mayoría de las veces es más que suficiente, pero si desea estar 100% seguro, agregue -ctambién para comparar el contenido de los archivos con el mismo nombre, hora y tamaño.

TLDR: solo dame un script para llamar

Aquí está. Llámalo así

diff-dirs Left_Dir Right_Dir [options]

Todas las opciones mencionadas anteriormente en la sección "Opciones adicionales que quizás desee utilizar" también se aplican aquí.

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

¿Como funciona?

Estamos llamando a rsync así:

rsync -rin ...

Usamos -i( --itemize-changes) para decirle a rsync que imprima una línea de salida para cada archivo que contiene información sobre cualquier diferencia entre los dos directorios. Necesitamos -nsuprimir el comportamiento normal de rsync (que es intentar sincronizar los dos directorios copiando / eliminando archivos). También necesitamos -rtrabajar recursivamente para todos los archivos / subdirectorios.

Llamamos a rsync tres veces:

Primera llamada : imprimir archivos que no existen en Dir_B. Necesitamos usar --ignore-existingpara ignorar los archivos que existen en ambos lados.

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

2da llamada : exactamente como antes pero intercambiamos el orden de DIR_A / DIR_B.

3ra llamada : Finalmente, usamos --existingpara verificar solo los archivos que aparecen en ambos directorios.

rsync -rin --existing $DIR_A/ $DIR_B/
ndemou
fuente
No sé sobre los demás, pero estoy usando tu guión. ¡Buen trabajo! gracias
Marinaio
Muchas gracias! Necesitaba algunos ajustes, los compartiré a continuación en caso de que alguien esté buscando algo similar. Primero, quería ejecutar rsync remoto como sudo user, para eso agregué --rsync-path="sudo rsync"a cada comando rsync. En segundo lugar, quería comparar el directorio local con el directorio remoto. Agregué --rsh "ssh -p1234"porque en mi caso SSH se está ejecutando en el puerto 1234. Luego llamé a script como diff-dirs [email protected]:/mnt/Vol1/dir1/ /localMnt/dir1 -c.
sen4ik
7

Según su pregunta, entiendo que no desea usar diff en ls , pero también puede usar diff de forma recursiva en los directorios:

diff -rq DIR1 DIR2
Camión
fuente
2

Me tomó algunos intentos para que esto funcione. La respuesta de Nils requiere que $TARGETtermine en un final /, como se explica por ジ ョ ー ジ.

Aquí hay una versión que agrega explícitamente el final /:

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

Esto proporciona la lista de archivos que existen debajo del ${SOURCE}directorio pero no debajo del ${TARGET}directorio.

Utilizo sedaquí para eliminar el inicio deletingde las líneas de salida y para imprimir solo esas líneas.

No uso la rsyncopción -cporque comparar el contenido del archivo sería mucho más lento para mis casos de uso, y comparar solo los tamaños de archivo y los tiempos de modificación también parece suficiente en estos casos. No tengo ninguna razón para sospechar que mis computadoras sufren problemas de distorsión del reloj o que algo cambió maliciosamente las marcas de tiempo. Además, el resultado de -cno puede cambiar la decisión de eliminar un archivo, solo la decisión de actualizar o mantener un archivo.

También uso -uy -a(en lugar de-r ), para que luego pueda reutilizar la línea de comando y cambiarla para copiar los directorios y archivos seleccionados de ${SOURCE}a ${TARGET}, de esta manera:

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

Tengo otra idea de hacer esto:

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

Puede hacer coincidir "FILEDETAIL ::" con la salida del comando. Además, puede cambiar la cadena "FILEDETAIL ::". El "% n" es el nombre del archivo.

-r Esto le dice a rsync que copie directorios recursivamente.

-n Esto hace que rsync realice una ejecución de prueba que no realiza ningún cambio.

zhao Tony
fuente