Linux: compare la estructura de directorios sin comparar archivos

55

¿Cuál es la forma mejor y más simple de comparar dos estructuras de directorios sin comparar realmente los datos en archivos? Esto funciona bien:

diff -qr dir1 dir2_

Pero es realmente lento porque también está comparando archivos. ¿Hay un interruptor para diff u otra herramienta cli simple para hacer esto?

Jonás
fuente
Por "estructura de directorio", ¿quiere decir solo las rutas de directorio, o las rutas de los archivos de directorio y los que no son de directorio?
intuido
Sí, carpetas y archivos.
Jonás
1
En ese caso, debe eliminar la -type dopción de la respuesta de @ slartibartfast o consultar mi respuesta.
intuido

Respuestas:

36

Lo siguiente (si sustituye el primer directorio por el directorio1 y el segundo por el directorio2) debe hacer lo que está buscando y rápidamente:

find directory1 -type d -printf "%P\n" | sort > file1
find directory2 -type d -printf "%P\n" | sort | diff - file1

El principio fundamental es que imprime todos los directorios, incluidas las rutas de subdirectorio en relación con el directorio baseN directorios.

Esto podría caerse (producir resultados extraños) si tiene retornos de carro en algunos de los nombres de directorio pero no en otros.

Slartibartfast
fuente
Esto no es bueno para mí, porque si un directorio contiene una carpeta con unos pocos miles de archivos, todos se enumeran individualmente, mientras que diff -rqsolo muestra que el directorio raíz existe en uno, y continúa.
Chris Jefferson
Como a cabo en punta (hace años) por intuido, al responder a la pregunta PO, el de tipo D se debe quitar para que los archivos son considerados en la comparación, así como directorios
user2746401
Entiendo y respeto esa lectura del enunciado del problema. Esa no era mi lectura en ese momento. ¿Recomienda que edite mi respuesta para responder a la pregunta actualizada? Estoy bien haciendo eso si crees que será útil para algunas personas, y estoy bien dejando la solución y el comentario tal como están ahora, lo que parece ser razonablemente efectivo.
Slartibartfast
34
vimdiff <(cd dir1; find . | sort) <(cd dir2; find . | sort)

le dará una buena visualización de lado a lado de las dos jerarquías de directorios con las secciones comunes dobladas.

garyjohn
fuente
Esta solución falla al azar. Cuando vim lee (o vuelve a leer) el descriptor de archivo temporal, ya no está.
Denilson Sá Maia
23

Usualmente uso rsyncpara esta tarea:

rsync -nav --delete DIR1/ DIR2

TENGA MUCHO CUIDADO de usar siempre laopción-naka--dry-run, o sincronizará (cambiará el contenido de) los directorios.

Esto comparará los archivos en función de los tiempos y tamaños de modificación de archivos ... Creo que eso es lo que realmente quieres, o al menos no te importa si lo hace. Tengo la sensación de que solo quieres que suceda más rápido , no que lo necesites para ignorar la diferencia entre el contenido del archivo. Si desea que no enumere archivos diferentes con nombres idénticos, creo que la adición de la --ignore-existingopción lo hará.

También tenga en cuenta que no poner un /al final de DIR1hará que compare el directorio DIR1 con el contenido de DIR2.

El resultado termina siendo un poco detallado, pero le mostrará qué archivos / directorios difieren. Los archivos / directorios presentes en DIR2y no en DIR1estarán precedidos por la palabra deleting.

Para algunas situaciones, la respuesta de @ slartibartfast puede ser más apropiada, aunque deberá eliminar la -type dopción para habilitar la lista de archivos que no son de directorio. rsyncserá más rápido si tiene una cantidad significativa de archivos / directorios para comparar.

intuido
fuente
Excelente respuesta En la salida de rsync es difícil notar el deleting...texto, pero probablemente sea una de las mejores formas de comparar archivos mientras se mantiene la velocidad. Las otras respuestas aquí son más rápidas cuando no se requiere diferenciar archivos ... como en el ejemplo de OP, pero realmente me gusta esta.
Joel Mellon
Esto es lo que buscaba. Tenía algunos archivos con diferentes tamaños en un par masivo de árboles de directorios, y quería saber cuáles. Esto logró ese objetivo en unos segundos.
suprjami
Tal vez sea una buena idea ejecutarlo con un usuario que tenga acceso de solo lectura. Me gusta, sudo -u nobody rsync -nav --delete d1 d2siempre que las banderas para 'otros' permitan la lectura.
user1182474
Al ejecutar esta solución, obtuve la "lista de archivos de construcción ... hecho \ n enviado X bytes recibidos Y bytes Z bytes / seg. El tamaño total es A aceleración es B" (donde sustituí XYZAB por números). ¿Eso significa que todo era idéntico? ¿Ya que no mencionó nada más específico? Gracias de antemano
Scott H
Para responder a mi propia pregunta, experimenté agregando diferentes archivos a cada uno, y parece que ningún archivo / directorio específico mencionado en la salida significa que todos son iguales.
Scott H
18

Similar a la respuesta de ls, pero si instala el árbol , puede

tree dir1 > out1
tree dir2 > out2
diff out1 out2
dígito
fuente
77
O para evitar los archivos tmp,diff <( tree dir1 ) <( tree dir2 )
Joel Mellon
1
Recomiendo ejecutar el árbol con la ibandera, que no imprime las líneas del árbol ( tree -i dir1, etc.). Si la estructura del directorio es diferente en un lugar, los otros archivos que coinciden pueden tener más o menos |símbolos en la salida del árbol, y diff capturará esas líneas incluso si las rutas de los archivos son idénticas.
askewchan
2
diff <(tree -i dir1) <(tree -i dir2) es, con mucho, la mejor respuesta. Estoy tentado a rechazar todas las respuestas que sugieren diff o rsync, ya que la pregunta dice explícitamente NO leer el contenido del archivo. NOTA: La sugerencia de usar dos tuberías requiere un uso cuidadoso de los espacios entre paréntesis, siga el ejemplo exactamente. Por ejemplo, para comparar dos volúmenes de 20G después de una copia de seguridad, la respuesta del árbol tomó aproximadamente 5 segundos. Los otros tomaron más de 20 minutos.
Jason Morgan
3

Estaba buscando una solución para este problema. La solución que más me gustó fue:

comm <(ls DIR1) <(ls DIR2)

Le da 3 columnas: 1 - archivos solo en DIR1, 2 - archivos solo en DIR2, 3 - archivos solo en DIR3 Para obtener más detalles, consulte esta publicación de blog.

kyrisu
fuente
¿Dónde se DIR3especifica? Todo lo que veo es DIR1y DIR2.
Michael Dorst
Lo probé, y (por lo que puedo decir) la salida era: todos los archivos sólo en DIR1en la columna 1 , todos los archivos sólo en DIR2en la columna 2 , y todos los archivos compartidos por tanto , en la columna 3 . Eso es algo útil, pero ¿sabe cómo se puede eliminar la columna 3 y dejar solo las diferencias? Tengo muchos archivos para ordenar, y la mayoría es idéntico. No necesito ver qué es lo mismo.
Michael Dorst
1
Además, descubrí que comm <(ls DIR1) <(ls DIR2)no funcionaba recursivamente. Para eso lo usé comm <(ls -R1 DIR1) <(ls -R1 DIR2). ls -Rrastrea los directorios de forma recursiva y ls -1(tenga en cuenta que es uno , no un L ) hace que lsimprima solo un nombre de archivo por línea.
Michael Dorst
@Michael: comm -3(ver man comm).
Zaz
2
ls > dir1.txt

ls > dir2.txt

Entonces simplemente diferencie las dos listas.

MDMarra
fuente
Parece que el OP quiere una jerarquía de caminos. Esto diferirá todos los archivos en el directorio actual. Es discutible, pero posible, que solo quiera directorios; él podría querer nombres de archivos en lugar de los contenidos de los archivos.
intuido
@intuited - tienes razón. Lo leí mal.
MDMarra
2

Esta es la solución óptima.

diff --brief -r dir1 dir2

- breve interruptor informa solo si los archivos difieren, no los detalles de la diferencia.

jkshah
fuente
1
El OP ya tiene -qen la pregunta, que es un alias para --brief. Esta respuesta no proporciona ninguna información nueva.
Michael Dorst
1
OP no quiere la comparación del contenido del archivo. But it's really slow because it's comparing files too.
Joel Mellon
1

use "diff -qr" para obtener los diferentes archivos y luego filtre la comparación de archivos con grep para obtener solo los nombres de archivo que solo están en uno de los directorios.

diff -qr dir1 dir2 | grep -v "Files.*differ" 
Anónimo
fuente
1

Esto funcionó para mi necesidad específica de encontrar archivos faltantes en los árboles que se espera que coincidan.

diff <( cd dir1; find * |sort ) <(cd dir2; find * | sort)
amhest
fuente
-3

Creo que solo rsync es userfull. ¿por qué?

diff es útil solo para estructuras que mantienen archivos y directorios. Diff no proporciona códigos de salida adecuados cuando usamos enlaces simbólicos. En esa situación, diff puede devolver 2 códigos de salida, incluso si src y dst son idénticos (tiempos, tamaños, nombres, marcas de tiempo, enlaces de software, etc.).

dir, el sistema de archivos no garantiza el orden de los archivos, incluso si los contenidos del directorio en src y dst son idénticos. Tal vez deberías filtrar la salida ls ordenándola. Pero ls puro solo muestra nombres de nodo.

tal vez la secuencia de comandos que incluye diff, cmp, test -X para los tipos de nodo será útil, pero recuerde sobre la sobrecarga realizada por muchas ejecuciones de prueba / cmp. El guión será muy lento.

Como de costumbre, si desea obtener información simple "dirs es / no es idéntico", debe usar rsync con la opción -n (dry). Si desea encontrar lo que es diferente, use el comando diff.

Znik
fuente
Me gustaría saber por qué las desventajas?
Znik