Me gustaría copiar un conjunto de archivos del directorio A al directorio B, con la advertencia de que si un archivo en el directorio A es idéntico a un archivo en el directorio B, ese archivo no debe copiarse (y, por lo tanto, su tiempo de modificación no debe ser actualizado). ¿Hay alguna manera de hacerlo con las herramientas existentes, sin escribir mi propio script para hacerlo?
Para elaborar un poco sobre mi caso de uso: estoy autogenerando un montón de .c
archivos en un directorio temporal (por un método que tiene que generarlos incondicionalmente), y cuando los vuelva a generar, me gustaría copiar solo los que han cambiado al directorio de origen real, dejando intactos los que no han cambiado (con sus viejos tiempos de creación) para que make
sepa que no es necesario volver a compilarlos. (Sin .c
embargo, no todos los archivos generados son archivos, así que necesito hacer comparaciones binarias en lugar de comparaciones de texto).
(Como nota: esto surgió de la pregunta que hice en https://stackoverflow.com/questions/8981552/speeding-up-file-comparions-with-cmp-on-cygwin/8981762#8981762 , donde estaba intentando para acelerar el archivo de script que estaba usando para hacer esta operación, pero se me ocurre que realmente debería preguntar si hay una mejor manera de hacerlo que escribir mi propio script, especialmente porque cualquier forma simple de hacerlo en un shell el script invocará algo así como cmp
en cada par de archivos, y comenzar todos esos procesos lleva demasiado tiempo).
fuente
diff -qr dirA dirB
para ver qué archivos son únicosdirA
ydirB
, respectivamente.rsync -avnc
o a lo largorsync --archive --verbose --dry-run --checksum
.Respuestas:
rsync es probablemente la mejor herramienta para esto. Hay muchas opciones en este comando, así que lea la página de manual . Creo que quieres la opción --checksum o la --ignore-times
fuente
-t
se especifica la opción) o al tiempo de sincronización (si-t
no se especifica)rsync
no. Si hago esto:mkdir src dest; echo a>src/a; rsync -c src/* dest; sleep 5; touch src/a; rsync -c src/* dest
, a continuación,stat dest/a
muestra su -mtime y ctime son 5 segundos más antiguas que las desrc/a
.--checksum
opción, y aunque linux.die.net/man/1/rsync no contiene absolutamente nada que implique que tenga algún efecto sobre si la fecha de modificación se actualiza, no obstante, deja la fecha de modificación de destino. intacto (Por otro lado, la--ignore-times
opción no tiene este efecto; con ella, la fecha de modificación aún se actualiza). Dado que esto parece estar completamente indocumentado, ¿puedo confiar en ello?rsync
el flujo de trabajo es: 1) verificar si el archivo necesita ser actualizado; 2) si es así, actualice el archivo. La--checksum
opción dice que no debe actualizarse, por lorsync
que no debe continuar con el paso 2).--ignore-times
sin--checksum
copiaría todos los archivos, y también actualizaría la marca de tiempo, incluso si los archivos son idénticos.Puedes usar el
-u
interruptor para que tecp
guste:Desde la página del manual:
fuente
-u
bandera y cómo funciona y cómo esto ayudaría al OP. Sin embargo, en este caso particular, no ayudaría al OP ya que copiaría archivos idénticos si fueran más nuevos y cambiaría sus marcas de tiempo, que es precisamente lo que el OP quiere evitar.Si bien el uso
rsync --checksum
es una buena forma general de "copiar si se cambia", en su caso particular, ¡hay una solución aún mejor!Si desea evitar la recompilación innecesaria de archivos, ¡debe usar ccache, que fue creado exactamente para este propósito! De hecho, no solo evitará recompilaciones innecesarias de sus archivos generados automáticamente, sino que también acelerará las cosas cada vez que lo haga
make clean
y volverá a compilar desde cero.A continuación, estoy seguro de que preguntarás: "¿Es seguro?" Bueno, sí, como señala el sitio web:
Y es fácil de usar simplemente agregándolo como un prefijo en la
CC=
línea de su archivo MAKE (o puede usar enlaces simbólicos, pero la forma del archivo MAKE probablemente sea mejor).fuente
ccache file.c -o file.o
o su equivalente, varios cientos de veces porque hay varios cientos defile.c
archivos. Cuando estaba haciendo eso concmp
, en lugar de hacerloccache
, me llevó varios minutos, ycmp
es tan liviano comoccache
. El problema es que, en Cygwin, iniciar un proceso lleva un tiempo no despreciable, incluso para un proceso completamente trivial.for f in src/*; do /bin/true.exe; done
lleva 30 segundos, así que sí. De todos modos, prefiero mi editor basado en Windows, y aparte de este tipo de problema de sincronización, Cygwin funciona bastante bien con mi flujo de trabajo como el lugar liviano para probar cosas localmente si no estoy cargando en los servidores de compilación. Es útil tener mi shell y mi editor en el mismo sistema operativo. :)Esto debería hacer lo que necesitas
Dónde:
fuente
-J
es específico de bsd; con GNU xargs lo es-I
), y no funciona correctamente si el mismo conjunto de archivos ya no existe en ambas ubicaciones (sitouch x/boo
entonces grep me daOnly in ./x: boo
que causa errores en la tubería). Use una herramienta creada para el trabajo, comorsync --checksum
.Me gusta usar unison a favor
rsync
porque es compatible con múltiples maestros, ya que configuré mis claves ssh y vpn por separado.Entonces, en mi crontab de solo un host, los dejo sincronizar cada 15 minutos:
Entonces puedo estar desarrollando en ambos lados y los cambios se propagarán. De hecho, para proyectos importantes, tengo hasta 4 servidores que reflejan el mismo árbol (3 ejecutan al unísono desde cron, señalando al que no lo hace). De hecho, los hosts Linux y Cygwin son mixtos, excepto que no espere sentido de enlaces blandos en win32 fuera del entorno cygwin.
Si sigue esta ruta, haga el espejo inicial en el lado vacío sin el
-batch
, es decirPor supuesto, hay una configuración para ignorar los archivos de respaldo, archivos, etc.
fuente
unison
opción que significa "no actualizar las fechas de última modificación del archivo". ¿Hay uno? De lo contrario, esta es una gran respuesta a un problema completamente diferente.-times
hace eso por mi Unison también tiene un modo de marcha en seco, creo.times=false
(o dejar-times
) haría eso. No sé cómo me perdí eso en la documentación antes. ¡Gracias!Si bien
rsync --checksum
es la respuesta correcta, tenga en cuenta que esta opción es incompatible--times
y que--archive
incluye--times
, por lo que si lo desearsync -a --checksum
, realmente necesita hacerlorsync -a --no-times --checksum
.fuente