Compare recursivamente dos directorios con diff -r sin salida en enlaces rotos

38

Estoy utilizando diff -r a ba los directorios de forma recursiva comparar una y b . A menudo sucede a pesar de que hay algunos enlaces rotos (los mismos enlaces rotos en tanto una y b directorios y apuntando a los mismos objetivos existentes, no).

diff luego envía mensajes de error para esos casos y sale con un código de salida distinto de cero, sin embargo, me gustaría que permanezca en silencio y salga con 0 ya que los directorios son los mismos en mi libro.

¿Cómo puedo hacer eso?

Marcus Junius Brutus
fuente
¿Todavía desea comparar los enlaces simbólicos (e identificados como equivalentes pero rotos), o es aceptable ignorar todos los enlaces simbólicos al hacer esta diferencia?
ire_and_curses
comparado e identificado como equivalente, no me importa si están rotos. Solo estoy tratando de verificar que mi rsync funcionó.
Marcus Junius Brutus

Respuestas:

24

Para la versión 3.3 o posterior diff, debe usar la --no-dereferenceopción, como se describe en la respuesta de Pete Harlan .

Desafortunadamente, las versiones anteriores de diff no admiten ignorar enlaces simbólicos :

Algunos archivos no son directorios ni archivos normales: son archivos inusuales como enlaces simbólicos, archivos especiales de dispositivos, canalizaciones con nombre y sockets. Actualmente, difftrata los enlaces simbólicos como archivos normales; trata otros archivos especiales como archivos normales si se especifican en el nivel superior, pero simplemente informa su presencia al comparar directorios. Esto significa que patchno puede representar cambios en dichos archivos. Por ejemplo, si cambia a qué archivo apunta un enlace simbólico, diffgenera la diferencia entre los dos archivos, en lugar del cambio al enlace simbólico.

diffOpcionalmente, debe informar cambios a archivos especiales especialmente, y patchdebe extenderse para comprender estas extensiones.

Si todo lo que desea es verificar un rsync (y presumiblemente arreglar lo que falta), entonces puede ejecutar el comando rsync por segunda vez. Si no desea hacer eso, entonces la suma de verificación del directorio puede ser suficiente.

Si realmente desea hacer esto diff, puede usar findpara omitir los enlaces simbólicos y ejecutar diff en cada archivo individualmente. Pasar los directorios de una y b como argumentos:

#!/bin/bash
# Skip files in $1 which are symlinks
for f in `find $1/* ! -type l`
do
    # Suppress details of differences
    diff -rq $f $2/${f##*/}
done

o como una línea:

for f in `find a/* ! -type l`;do diff -rq $f b/${f##*/};done

Esto identificará archivos que difieren en contenido, o archivos que están en a pero no en b .

Tenga en cuenta que:

  • ya que estamos omitiendo enlaces simbólicos por completo, esto no se notará si los nombres de enlaces simbólicos no están presentes en b . Si lo necesita, necesitaría un segundo pase de búsqueda para identificar todos los enlaces simbólicos y luego verificar explícitamente su existencia en b .
  • No se identificarán archivos adicionales en b , ya que la lista se construye a partir del contenido de a . Esto probablemente no sea un problema para su rsyncescenario.
ire_and_curses
fuente
El script propuesto no funciona de forma recursiva para ningún directorio presente en el directorio 'a' (las rutas creadas para 'b' usando b / $ {f ## *} no son correctas).
Marcus Junius Brutus
@MarcusJuniusBrutus - Sí, tienes razón. Creo que la solución es eliminar un #, por ejemplo, for f in encontrar un / *! -tipo l ;do echo $f b/${f#*/};done. Sin embargo, no tengo tiempo para probar esto ahora. Avísame si eso funciona.
ire_and_curses
Que es mejor sin embargo, todavía puede confundir las rutas de los archivos en muchos casos. El script (con un # eliminado) parece necesitar ser invocado desde un directorio directamente sobre 'a' para funcionar.
Marcus Junius Brutus
Esta respuesta se vuelve obsoleta cuando se usa GNU diff 3.3 (ver publicaciones a continuación)
Bernd Gloss
El script anterior tiene varios problemas, debido a que primero encuentra todos los nombres de archivo y los alimenta a una línea de comando expandida. (1) Solo funcionará con pequeñas colecciones de archivos desde entonces. (2) Cualquier nombre de archivo con carácter especial (incluso un espacio) no se procesará. (3) Utilice siempre en $(xxx)lugar de backticks. La simetría de Backticks los hace menos legibles y evita el anidamiento. Con respecto a 1 y 2 ver stackoverflow.com/questions/11366184/…
Stéphane Gourichon
19

Desde la versión 3.3, GNU diffno admite la desreferenciación de enlaces simbólicos, pero luego compara las rutas a las que apuntan.

Instale GNU diffutils> = 3.3 y use la --no-dereferenceopción; No hay una opción corta para eso.

El diagnóstico será silencioso si es igual o:

Enlaces simbólicos /tmp/noderef/a/symlinky /tmp/noderef/b/symlinkdiferentes

Philippe De Muyter
fuente
Ahora, si solo mostrara los cambios de contenido, como si el enlace simbólico fuera un archivo normal ...: - /
lindes
6

Puedes usar una versión más nueva de diff

El diffGNU diffutils3.3 incluye una --no-dereferenceopción que le permite comparar los enlaces simbólicos en sí mismos en lugar de sus objetivos. Informa si difieren, es silencioso si están de acuerdo y no le importa si están rotos.

No sé cuándo se agregó la opción; No está presente en 2.8.1.

Pete Harlan
fuente
Puedo confirmar si tampoco existe en diff (GNU diffutils) 3.2
Elder Geek