Tengo dos unidades con los mismos archivos, pero la estructura del directorio es totalmente diferente.
¿Hay alguna forma de 'mover' todos los archivos en el lado de destino para que coincidan con la estructura del lado de origen? ¿Con un guión quizás?
Por ejemplo, la unidad A tiene:
/foo/bar/123.txt
/foo/bar/234.txt
/foo/bar/dir/567.txt
Mientras que la unidad B tiene:
/some/other/path/123.txt
/bar/doo2/wow/234.txt
/bar/doo/567.txt
Los archivos en cuestión son enormes (800 GB), por lo que no quiero volver a copiarlos; Solo quiero sincronizar la estructura creando los directorios necesarios y moviendo los archivos.
Estaba pensando en un script recursivo que encontraría cada archivo de origen en el destino, luego lo movería a un directorio coincidente, creándolo si fuera necesario. Pero, ¡eso está más allá de mis habilidades!
Aquí se dio otra solución elegante: /superuser/237387/any-way-to-sync-directory-structure-when-the-files-are-already-on-both-sides/238086
Respuestas:
Voy a ir con Gilles y señalarle a Unison como sugiere j hasen . Unison fue DropBox 20 años antes de DropBox. Código sólido que muchas personas (incluido yo mismo) usamos todos los días, vale la pena aprenderlo. Aún así,
join
necesita toda la publicidad que pueda obtener :)Esta es solo la mitad de una respuesta, pero tengo que volver al trabajo :)
Básicamente, quería demostrar la
join
utilidad poco conocida que hace justamente eso: une dos tablas en algún campo.Primero, configure un caso de prueba que incluya nombres de archivos con espacios:
(edite algunos nombres de directorio y / o archivo en
new
).Ahora, queremos construir un mapa: hash -> nombre de archivo para cada directorio y luego usarlo
join
para hacer coincidir los archivos con el mismo hash. Para generar el mapa, ponga lo siguiente enmakemap.sh
:makemap.sh
escupe un archivo con líneas del formulario, 'hash "nombre de archivo"', así que solo nos unimos en la primera columna:Esto genera lo
moves.txt
que se ve así:El siguiente paso sería hacer los movimientos, pero mis intentos se atascaron en las citas ...
mv -i
ymkdir -p
deberían ser útiles.fuente
join
Es realmente interesante. Gracias por llamar mi atención.join
entrada?Hay una utilidad llamada unísono:
http://www.cis.upenn.edu/~bcpierce/unison/
Descripción del sitio:
Tenga en cuenta que Unison solo detecta archivos movidos en la primera ejecución si al menos una de las raíces es remota, por lo que incluso si está sincronizando archivos locales, úsela
ssh://localhost/path/to/dir
como una de las raíces.fuente
Use Unison como lo sugiere hasen j . Dejo esta respuesta como un ejemplo de scripts potencialmente útil o para usar en un servidor con solo utilidades básicas instaladas.
Asumiré que los nombres de los archivos son únicos en toda la jerarquía. También supondré que ningún nombre de archivo contiene una nueva línea, y que los árboles de directorios solo contienen directorios y archivos normales.
Primero recopile los nombres de archivo en el lado de origen.
Luego mueva los archivos a su lugar en el lado de destino. Primero, cree un árbol de archivos aplanado en el lado de destino. Úselo en
ln
lugar demv
si desea mantener los enlaces duros en la antigua jerarquía.Si faltan algunos archivos en el destino, cree un archivo plano similar
/A.staging
y use rsync para copiar los datos del origen al destino.Ahora cambie el nombre de los archivos a su lugar.
Equivalentemente:
Finalmente, si le interesan los metadatos de los directorios, llame a rsync con los archivos que ya están en su lugar.
Tenga en cuenta que no he probado los fragmentos en esta publicación. Úselo bajo su propio riesgo. Por favor reporte cualquier error en un comentario.
fuente
Particularmente, si la sincronización continua sería útil, podría intentar descubrir git-annex .
Es relativamente nuevo; No he tratado de usarlo yo mismo.
Puedo sugerirlo porque evita mantener una segunda copia de los archivos ... esto significa que tiene que marcar los archivos como de solo lectura ("bloqueado"), como ciertos sistemas de control de versiones que no son Git.
Los archivos se identifican mediante la extensión de archivo sha256sum + (de forma predeterminada). Por lo tanto, debería poder sincronizar dos repositorios con contenido de archivo idéntico pero nombres de archivo diferentes, sin tener que realizar escrituras (y en una red de bajo ancho de banda, si lo desea). Por supuesto, tendrá que leer todos los archivos para poder sumarlos.
fuente
Qué tal algo como esto:
Esto supone que los nombres de los archivos que desea sincronizar son únicos en todo el disco: de lo contrario, no hay forma de que pueda automatizarse por completo (sin embargo, puede proporcionar un aviso para que el usuario elija qué archivo elegir si hay más).
La secuencia de comandos anterior funcionará en casos simples, pero puede fallar si
name
contiene símbolos que tienen un significado especial para expresiones regulares. Lagrep
lista de archivos también puede llevar mucho tiempo si hay muchos archivos. Puede considerar traducir este código para usar hashtable que asignará nombres de archivos a rutas, por ejemplo, en Ruby.fuente
grep
línea? ¿Solo encuentra la ruta completa del archivo correspondientedstlist
?ln
esto crea enlaces simbólicos. Puede emplearmv
para mover los archivos, pero tenga cuidado de sobrescribir los existentes. Además, es posible que desee limpiar directorios vacíos, si los hay, después de alejar los archivos. Sí, esegrep
comando busca una línea que termina en el nombre del archivo, revelando así la ruta completa en la unidad de destino.Asumiendo que los nombres de los archivos base son únicos en los árboles, es bastante sencillo:
Si desea limpiar los viejos directorios vacíos, use:
fuente
También me enfrenté a este problema. La solución basada en md5sum no funcionó para mí, porque sincronizo mis archivos con un
webdav
montaje. Calcular sumas md5sum en elwebdav
destino también significaría operaciones de archivos grandes.Hice un pequeño script
reorg_Remote_Dir_detect_moves.sh
(en github) que intenta detectar los archivos más movidos y luego crea un nuevo script de shell temporal con varios comandos para ajustar el directorio remoto. Como solo cuido los nombres de archivo, el script no es la solución perfecta.Por seguridad, se ignorarán varios archivos: A) Archivos con los mismos nombres (del mismo comienzo) en cada lado, y B) Archivos que solo están en el lado remoto. Serán ignorados y omitidos.
Los archivos omitidos serán manejados por su herramienta de sincronización preferida (por ejemplo
rsync, unison
, ...), que debe usar después de ejecutar el script de shell temporal.¿Entonces mi guión es útil para alguien? Si es así (para que quede más claro) hay tres pasos:
reorg_Remote_Dir_detect_moves.sh
(en github)/dev/shm/REORGRemoteMoveScript.sh
=> ejecutar esto para hacer los movimientos (será rápido en montadowebdav
)rsync, unison
, ...)fuente
Aquí está mi intento de respuesta. Como advertencia, toda mi experiencia en scripts proviene de bash, por lo que si está utilizando un shell diferente, los nombres de comandos o la sintaxis pueden ser diferentes.
Esta solución requiere la creación de dos scripts separados.
Este primer script es responsable de mover los archivos en la unidad de destino.
El segundo script crea el archivo de mapa md5 usado por el primer script y luego llama al primer script en cada archivo en la unidad de destino.
Básicamente, lo que está sucediendo es que los dos scripts simulan una matriz asociativa con
$md5_map_file
. Primero, se calculan y almacenan todos los md5 para los archivos en la unidad fuente. Asociados con los md5 están las rutas relativas desde la raíz de la unidad. Luego, para cada archivo en la unidad de destino, se calcula el md5. Usando este md5, se busca la ruta de ese archivo en la unidad de origen. El archivo en la unidad de destino se mueve para que coincida con la ruta del archivo en la unidad de origen.Hay un par de advertencias con este script:
fuente
md5sum
parece que no es lo que hay que usar aquí. (Por cierto,rsync
tiene un modo en el que no calcula sumas de verificación.)