bash - programas - scripts linux ejercicios resueltos
Cómo comparar archivos con los mismos nombres en dos directorios diferentes utilizando un script de shell (6)
Antes de pasar a usar SVN, solía administrar mi proyecto simplemente manteniendo un directorio /develop/
y editando y probando archivos allí, luego moviéndolos al directorio /main/
. Cuando decidí cambiarme a SVN, necesitaba estar seguro de que los directorios estaban realmente sincronizados.
Entonces, ¿cuál es una buena forma de escribir un script de shell [bash] para comparar recursivamente los archivos con el mismo nombre en dos directorios diferentes?
Nota: Los nombres de directorio utilizados anteriormente son solo para muestra. No recomiendo almacenar tu código en el nivel superior :).
El comando diff tiene una opción -r para comparar recursivamente los directorios:
diff -r /develop /main
El diff que tengo disponible permite las diferencias recursivas:
diff -r main develop
Pero con un script de shell:
( cd main ; find . -type f -exec diff {} ../develop/{} '';'' )
La respuesta clásica (System V Unix) sería dircmp dir1 dir2
, que era un script de shell que enumeraría los archivos encontrados en dir1 pero no dir2 o en dir2 pero no dir1 al inicio (primera página de salida, desde el comando pr
, así paginado con encabezados), seguido por una comparación de cada archivo común con un análisis (el mismo, diferente, directorio fueron los resultados más comunes).
Esto parece estar en proceso de desaparición. Tengo una reimplementación independiente disponible si lo necesita. No es ciencia espacial ( cmp
es tu amigo).
[Leí en algún lado que responder tus propias preguntas está bien, así que aquí va :)]
Intenté esto, y funcionó bastante bien
[/]$ cd /develop/
[/develop/]$ find | while read line; do diff -ruN "/main/$line" $line; done |less
Puede optar por comparar solo archivos específicos [por ejemplo, solo los .php ones] editando la línea anterior como
[/]$ cd /develop/
[/develop/]$ find -name "*.php" | while read line; do diff -ruN "/main/$line" $line; done |less
¿Alguna otra idea?
aquí hay un ejemplo de un guión mío (algo desordenado), dircompare.sh , que:
- ordenar los archivos y directorios en matrices, según el directorio en el que se encuentren (o ambos), en dos pases recursivos
- Los archivos que ocurren en ambos directorios, se ordenan de nuevo en dos matrices, dependiendo de si
diff -q
determina si difieren o no - para aquellos archivos que las reclamaciones de
diff
son iguales, muestre y compare las marcas de tiempo
Espero que se pueda encontrar útil. ¡Saludos!
EDIT2: ( En realidad, funciona bien con archivos remotos: el problema fue la señal Ctrl-C no controlada durante una operación de diferencia entre archivo local y remoto, lo que puede llevar un tiempo; el script ahora se actualizó con una trampa para manejar eso; edición previa a continuación para referencia ):
EDITAR: ... excepto que parece bloquear mi servidor para un directorio ssh remoto (que traté de usar sobre ~/.gvfs
) ... Así que esto ya no es bash
, pero una alternativa que supongo es usar rsync
, aquí hay una ejemplo:
$ # get example revision 4527 as testdir1
$ svn co https://openbabel.svn.sf.net/svnroot/openbabel/openbabel/trunk/data@4527 testdir1
$ # get earlier example revision 2729 as testdir2
$ svn co https://openbabel.svn.sf.net/svnroot/openbabel/openbabel/trunk/data@2729 testdir2
$ # use rsync to generate a list
$ rsync -ivr --times --cvs-exclude --dry-run testdir1/ testdir2/
sending incremental file list
.d..t...... ./
>f.st...... CMakeLists.txt
>f.st...... MACCS.txt
>f..t...... SMARTS_InteLigand.txt
...
>f.st...... atomtyp.txt
>f+++++++++ babel_povray3.inc
>f.st...... bin2hex.pl
>f.st...... bondtyp.h
>f..t...... bondtyp.txt
...
Tenga en cuenta que:
- Para obtener lo anterior, no debe olvidar barras inclinadas
/
al final de los nombres de directorio enrsync
-
--dry-run
- simular solamente, no actualizar / transferir archivos -
-r
- recurse en directorios -
-v
- verboso (pero no relacionado con la información de cambios de archivo) -
--cvs-exclude
- ignorar archivos.svn
-
-i
- "--itemize-changes: genera un resumen de cambios para todas las actualizaciones"
Aquí hay un breve extracto de man rsync
que explica la información mostrada por -i
(por ejemplo, las >f.st......
anteriores):
The "%i" escape has a cryptic output that is 11 letters long.
The general format is like the string YXcstpoguax, where Y is
replaced by the type of update being done, X is replaced by the
file-type, and the other letters represent attributes that may
be output if they are being modified.
The update types that replace the Y are as follows:
o A < means that a file is being transferred to the remote
host (sent).
o A > means that a file is being transferred to the local
host (received).
o A c means that a local change/creation is occurring for
the item (such as the creation of a directory or the
changing of a symlink, etc.).
...
The file-types that replace the X are: f for a file, a d for a
directory, an L for a symlink, a D for a device, and a S for a
special file (e.g. named sockets and fifos).
The other letters in the string above are the actual letters
that will be output if the associated attribute for the item is
being updated or a "." for no change. Three exceptions to this
are: (1) a newly created item replaces each letter with a "+",
(2) an identical item replaces the dots with spaces, and (3) an
....
Un poco críptico, de hecho, pero al menos muestra una comparación básica de directorios a través de ssh
. ¡Aclamaciones!
diff -rqu /develop /main
Solo le dará un resumen de los cambios de esa manera :)
Si quieres ver solo archivos nuevos / faltantes
diff -rqu /develop /main | grep "^Only
Si quieres que estén al descubierto:
diff -rqu /develop /main | sed -rn "/^Only/s/^Only in (.+?): //1/p"