diff para mostrar solo los nombres de archivo

244

Estoy buscando ejecutar un comando de Linux que comparará recursivamente dos directorios y generará solo los nombres de archivo de lo que es diferente. Esto incluye todo lo que está presente en un directorio y no en el otro o viceversa, y las diferencias de texto.

barfoon
fuente

Respuestas:

375

Desde la página de manual de diff:

-q   Informe solo si los archivos difieren, no los detalles de las diferencias.
-r   Al comparar directorios, compare recursivamente cualquier subdirectorio encontrado.

Comando de ejemplo:

diff -qr dir1 dir2

Ejemplo de salida (depende del entorno local):

$ ls dir1 dir2
dir1:
same-file  different  only-1

dir2:
same-file  different  only-2
$ diff -qr dir1 dir2
Files dir1/different and dir2/different differ
Only in dir1: only-1
Only in dir2: only-2
John Kugelman
fuente
Gracias: la diffpágina de manual de CentOS 7 describe -qcomo "informar solo cuando los archivos difieren", lo cual es menos claro que lo que escribió.
Capítulo
2
Esto compara el contenido real de los archivos, que a menudo es lo que uno quiere, sin embargo, la respuesta rsync ofrece la opción de mirar solo los nombres y tamaños de los archivos, y no el contenido; eso es a veces deseable.
steveb
También funciona en macOS.
Marius Soutier
Además, puede incluir un -x PATTERNcomando para excluir ciertos subdirectorios. Por ejemplo, diff -qr repo1 repo2 -x ".git" comparará dos directorios pero excluirá rutas de archivos con ".git" en ellos.
ViFI
27

También puedes usar rsync

rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out
boksiora
fuente
66
--size-onlyextrañará archivos de tamaño idéntico pero contenido diferente, por ejemplo, viejo / version.txt "29a" nuevo / version.txt "29b" . Utilice en su lugar: rsync -ric --dry-run old/ new/donde el argumento "-i" permite obtener la lista de archivos directamente a través dersync -ric --dry-run old/ new/ | cut -d" " -f 2
iolsmit
66
Esto es excelente si solo está buscando archivos faltantes (especialmente en los recursos compartidos de red), porque no compara el contenido. Esto me ayudó a encontrar algunos archivos que fallaron al migrar a un nuevo NAS.
OverZealous
44
Asegúrese de incluir la barra diagonal final para las rutas especificadas en la línea de comando de rsync. ¡Sin ellos, esto no funcionará correctamente, y rsync probablemente solo enumerará todos los nombres de archivo!
Vladimir Panteleev
2
Con respecto a los comentarios sobre no verificar el contenido. Esto es a veces deseable, al menos como primer paso.
steveb
13

Si desea obtener una lista de archivos que están solo en un directorio y no sus subdirectorios y solo sus nombres de archivo:

diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'

Si desea enumerar recursivamente todos los archivos y directorios que son diferentes con sus rutas completas:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'

De esta manera, puede aplicar diferentes comandos a todos los archivos.

Por ejemplo, podría eliminar todos los archivos y directorios que están en dir1 pero no dir2:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}
DAKOTA DEL NORTE
fuente
9

En mi sistema Linux para obtener solo los nombres de archivo

diff -q /dir1 /dir2|cut -f2 -d' '
gerardw
fuente
77
No pongo nombres de archivo con espacios en mi sistema Linux. ;)
gerardw
66
No quise imputarte esto ... ;-p Solo como una pista para alguien que sí ...
michuelnik
no funciona para mi La estructura de mi directorio es la siguienteaudit-0.0.234/audit-data-warehouse-0.0.234/ audit-0.0.235/audit-data-warehouse-0.0.235/
Alex Raj Kaliamoorthy
diff -qrN /dir1 /dir2 | cut -f2 -d' 'funciona bien para mi!
Francesco
9

El enfoque de ejecución diff -qr old/ new/tiene un inconveniente importante: puede faltar archivos en directorios recién creados. Por ejemplo, en el ejemplo a continuación, el archivo data/pages/playground/playground.txtno está en la salida, diff -qr old/ new/mientras que el directorio sí lo data/pages/playground/está (busque playground.txt en su navegador para compararlo rápidamente). También publiqué la siguiente solución en Unix y Linux Stack Exchange , pero también la copiaré aquí:

Para crear una lista de archivos nuevos o modificados mediante programación, la mejor solución que se me ocurre es usar rsync , sort y uniq :

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

Permítanme explicar con este ejemplo: queremos comparar dos versiones de dokuwiki para ver qué archivos se cambiaron y cuáles se crearon recientemente.

Buscamos los tars con wget y los extraemos en los directorios old/y new/:

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

Ejecutar rsync de una manera puede perder archivos recién creados como se muestra aquí en la comparación de rsync y diff:

rsync -rcn --out-format="%n" old/ new/

produce el siguiente resultado:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

Al ejecutar rsync solo en una dirección, se pierden los archivos recién creados y, al revés, se perderían los archivos eliminados, compare la salida de diff:

diff -qr old/ new/

produce el siguiente resultado:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

Ejecutar rsync en ambos sentidos y ordenar la salida para eliminar duplicados revela que el directorio data/pages/playground/y el archivo data/pages/playground/playground.txtse perdieron inicialmente:

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

produce el siguiente resultado:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync se ejecuta con estos argumentos:

  • -r "recurrir a directorios",
  • -c para comparar también archivos de tamaño idéntico y solo "omitir en función de la suma de comprobación, no de mod-time & size",
  • -n para "realizar una ejecución de prueba sin realizar cambios", y
  • --out-format="%n" "generar actualizaciones utilizando el FORMATO especificado", que es "% n" aquí solo para el nombre del archivo

La salida (lista de archivos) de rsyncen ambas direcciones se combina y ordena usando sort, y esta lista ordenada se condensa eliminando todos los duplicados conuniq

Iolsmit
fuente
¿No podría simplemente ejecutarlo al revés ( diff new/ old/) para ver qué directorios se eliminaron?
Jacques
Ejecutar diff -qr new/ old/en el ejemplo anterior con los tars dokuwiki produce el mismo resultado que diff -qr old/ new/, es decir, ve que el directorio es nuevo / falta pero no los archivos en él
iolsmit
-4
rsync -rvc --delete --size-only --dry-run source dir target dir
mayank
fuente