herramientas de diferencias de Linux: crea una list de files modificados

¿Cómo creo una list de files modificados mediante progtwigción utilizando las herramientas de command-line de Linux? No estoy interesado en la diferencia en ningún file en particular (delta, parche). Solo quiero tener una list de files nuevos o modificados en comparación con la versión anterior del producto. Para que pueda publicar una nueva actualización del producto.

actualización: diff -qr no produce salida muy conveniente. La salida de diff -qr también necesita ser procesada. ¿Hay alguna forma mejor?

Tengo un enfoque simple para esto: use el modo rsync-preview:

 rsync -aHSvn --delete old_dir/ new-dir/ 

Los files que se muestran como "para ser eliminados" por ese command serán los "nuevos" files. Los otros que van a ser transferidos han cambiado de alguna manera. Vea la página rsync-man para más detalles.

Puede usar la function diff : ver las opciones -q y -r

 -q --brief Output only whether files differ. -r --recursive Recursively compare any subdirectories found. 

Ejemplo:

 diff -qr dir1 dir2 

El package diffutils incluye una herramienta lsdiff . Solo pase la salida de diff -u a lsdiff:

 diff -u --other-diff-options path1 path2 | lsdiff 

Solo tocaría un file en el momento de cada actualización, y luego podrá encontrar los files que fueron modificados desde entonces con find /tree/location -newer /last/update/file -print

Para tomar solo el nombre de los files que cambiaron, uso este command:

 diff -r dirt1 dir2 --brief | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/' 

Si necesita excluir algunos files como files de object o biblioteca, puede usar:

 diff -r dirt1 dir2 --brief --exclude "*.o" --exclude "*.a" | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/' 

Debes get el resultado deseado usando:

 diff -r --brief dir1/ dir2/ 

Esto podría hacer el truco:

 compare_dirs() { # Shows which files and directories exist in one directory but not both if [ $# -ne 2 ] then echo "Usage: compare_dirs dir1 dir2" >&2 return 2 fi for path do if [ ! -d "$path" ] then echo "Not a directory: $path" >&2 return 1 fi done comm -3 \ <(cd -- "$1" && find . -printf '%P\0' | sort -z | quote_shell) \ <(cd -- "$2" && find . -printf '%P\0' | sort -z | quote_shell) } 

Normalmente colocas los files en algún tipo de sistema de control de versiones como SubVersion o git, ya que pueden hacer esto para ti desde el primer momento.

Pero podría hacer una secuencia de commands rápida con un bucle for en dir1 y luego comparar cada file con el de dir2. El bucle for puede ver el código de salida de diff para saber si los files eran diferentes.

Tal vez algo como esto:

 for f in `(cd dir1 ; find .)` do diff $f ../dir2/$f if [ "$?" == "0" ] then echo same else echo diff: $f fi done 

Nota: El script no está probado, por lo que el ejemplo anterior es "pseudocódigo inspirado en bash" …


Vamos a ir otra vez, pero con git

Crea algunos files de ejemplo para jugar

 mkdir -p dir1/test1/test11 mkdir -p dir1/test1/test12 mkdir -p dir1/test1/test13 echo "Test1" >> dir1/test1/test11/t1.txt echo "Test2" >> dir1/test1/test12/t2.txt echo "Test3" >> dir1/test1/test13/t3.txt #And a dir to work in mkdir gitdir 

Luego ingrese el directory e importe el dir1

 cd gitdir/ git init . cp -r ../dir1/* . git add . git commit -m 'dir1' 

Sal y modifica dir1 (para que se convierta en tu dir2)

 cd .. echo "Test2" > dir1/test1/test11/t1.txt 

Luego ve al directory de git e importa el nuevo directory

 cd gitdir/ cp -r ../dir1/* . 

Ahora pregunta a git qué ha cambiado (con el command de estado)

 git status -s 

El resultado es una list con los cambios, que se ve así:

  M test1/test11/t1.txt 

Tal vez estarías más feliz con algo diferente. Prueba git .

Haz esto como un ejemplo:

 mkdir a cd a git init touch b git add . && git commit -m "Empty file" git status echo c >> b git status git add . && git commit -m "Full file" git status 

git rastreará tus files por ti. El git status command git status le mostrará todos los files que se han modificado desde la última confirmación.

Para crear una list de files nuevos o modificados mediante progtwigción, la mejor solución que podría encontrar 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 lanzamientos de dokuwiki para ver qué files fueron cambiados y cuáles fueron creados nuevamente.

Traemos los tars con wget y los extraemos en los directorys 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 pasar por alto los files recién creados, ya que la comparación de rsync y diff se muestra aquí:

 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 files recién creados y, al revés, se perderán los files eliminados, y se comparará el resultado 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 orderar la salida para eliminar duplicates revela que el directory data/pages/playground/ y el file data/pages/playground/playground.txt se 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 arguments:

  • -r para "recurse en directorys",
  • -c para comparar también files de tamaño idéntico y solo "salto basado en sum de comprobación, no time-time y tamaño",
  • -n para "realizar una ejecución de testing sin cambios realizados", y
  • --out-format="%n" para "generar actualizaciones utilizando el FORMATO especificado", que es "% n" aquí solo para el nombre del file

La salida (list de files) de rsync en ambas direcciones se combina y ordera usando sort , y esta list orderada se condensa al eliminar todos los duplicates con uniq

Esto es similar a rsync: muestra cuándo se va a sobrescribir el file más nuevo en el destino (se le pide más tarde, aunque no es un duplicado).

Como se indica en la pregunta, "diff -q -r" puede requerir algún procesamiento para ser útil. La pregunta no especificaba la forma del resultado; las respuestas dan diferentes types de informes.

rsync es una herramienta útil para este propósito porque es mucho más rápido que diff . Sin embargo, la solución sugerida por @nils es mucho más detallada (y enumera más files) que las diferencias reales entre los treees de directorys antiguos / nuevos. Por ejemplo, comparando eso con el script que escribí para esa respuesta, y ejecutándome con la misma información,

  • @nils answer produce 605 líneas (aparentemente porque incluye cambios de directory ),
  • "diff -q -r" produce 352 líneas después de ejecutarse durante varios minutos, y
  • mi script muestra 252 líneas (files reales cambiados, agregados o eliminados)

Para hacer que diff represente adecuadamente los nuevos files, también necesita la opción -N (que no veo en ninguna de las respuestas sugeridas). Sin embargo, dado que es mucho más lento (órdenes de magnitud) que rsync , mejorar el performance de este último parece ser el path a seguir.

Otras lecturas

  • diff – compare files línea por línea
  • rsync: una herramienta de copy de files rápida, versátil, remota (y local)