¿Cómo copiar-fusionar dos directorios?

113

Tengo dos directorios de imágenes e imágenes2 con esta estructura en Linux:

/images/ad  
/images/fe  
/images/foo  

... y otras 4000 carpetas

y el otro es como:

/images2/ad  
/images2/fe  
/images2/foo

... y otras 4000 carpetas

Cada una de estas carpetas contiene imágenes y los nombres de los directorios bajo imágenes e imágenes2 son exactamente iguales, sin embargo, su contenido es diferente. Entonces quiero saber cómo puedo copiar-fusionar las imágenes de / images2 / ad en images / ad, las imágenes de / images2 / foo en images / foo y así sucesivamente con todas las 4000 carpetas.

ssierral
fuente
1
¿Los archivos finales tienen el mismo nombre en ambos directorios?
Simply_Me
No ... por ejemplo en imágenes / anuncios son 1.jpg, 2.jpg y 3.jpg. Pero en images2 / ad son 4.jpg y 5.jpg
ssierral
44
@AmirAliAkbari, no creo que sea un duplicado, la otra pregunta básicamente es '¿se fusiona mv?' (respuesta: no) Esta pregunta trata sobre cómo fusionar 2 jerarquías de directorios.
maxschlepzig

Respuestas:

174

Este es un trabajo para rsync . No es beneficioso hacer esto manualmente con un bucle de shell a menos que desee mover el archivo en lugar de copiarlo.

rsync -a /path/to/source/ /path/to/destination

En tu caso:

rsync -a /images2/ /images/

(Observe la barra inclinada final images2, de lo contrario se copiaría /images/images2).

Si existen imágenes con el mismo nombre en ambos directorios, el comando anterior se sobrescribirá /images/SOMEPATH/SOMEFILEcon /images2/SOMEPATH/SOMEFILE. Si desea reemplazar solo archivos antiguos, agregue la opción -u. Si desea mantener siempre la versión /images, agregue la opción --ignore-existing.

Si desea mover los archivos /images2, con rsync, puede pasar la opción --remove-source-files. Luego, rsync copia todos los archivos a su vez y elimina cada archivo cuando está listo. Esto es mucho más lento que moverse si los directorios de origen y destino están en el mismo sistema de archivos.

Gilles
fuente
14
..add -P si desea ver el progreso ..
Meetai.com
1
Yo añadiría que no hay beneficio de usar un bucle cáscara difícil aquí, incluso si usted no desea moverlos en lugar de copiarlos en ese caso, sólo tiene que utilizar rsync, a continuación rm -r /images.
Comodín
1
También me gustaría señalar que es importante incluir las barras diagonales finales para cada directorio . Por ejemplo, si simplemente ejecutó rsync -a images images2, simplemente copiará images2 en imágenes en lugar de fusionarlas.
Kyle Challis
1
@ s3cur3 Oh. De 2 a (implícito) 1. Eso no es intuitivo. Gracias, arreglé mi respuesta.
Gilles
1
@MaxCoplan No. Rsync no es una herramienta interactiva.
Gilles
43

La mejor opción, como ya se publicó, es por supuesto rsync. Sin embargo, también el unísono sería una gran pieza de software para hacer este trabajo. Ambos se pueden usar en varios sistemas operativos.

Rsync

rsync se sincroniza en una dirección desde el origen hasta el destino. Por lo tanto, la siguiente declaración

rsync -avh --progress Source Destination

sincroniza todo, desde el origen hasta el destino . La carpeta fusionada reside en Destino .

-a significa "archivo" y copia todo de forma recursiva desde el origen hasta el destino, preservando casi todo.

-v da más salida ("detallado").

-h para humanos legibles.

- Progreso para mostrar cuánto trabajo se realiza.

Si solo desea actualizar la carpeta de destino con los archivos más nuevos de la carpeta de origen:

rsync -avhu --progress source destination

Unísono

el unísono se sincroniza en ambas direcciones. Por lo tanto, la siguiente declaración

unison Source Destination

sincroniza ambos directorios en ambas direcciones y finalmente origen es igual a destino. Es como hacer rsync dos veces desde el origen hasta el destino y viceversa.

Para usos más avanzados, consulte las páginas de manual o los siguientes sitios web:

  1. https://www.cis.upenn.edu/~bcpierce/unison/
  2. https://rsync.samba.org/
debiarca
fuente
2
Quiero mencionar que la ruta correcta a la carpeta debe ser con la barra diagonal final al final rsync -avh --progress source/ destination/, de lo contrario, la carpeta de origen se creará en la carpeta de destino, al menos en mi caso así.
electroide
Esto funciona muy bien para mí (con la barra inclinada final en las carpetas). ¡Gracias!
Leopoldo Sanczyk
5
for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done

Recorra todo el contenido del images2uso de un globo expandido (para evitar los problemas con el análisis ls) y luego mvel contenido de esos elementos en la entrada correspondiente images. Utiliza basenamepara despojar al líder images2de la ruta global.

Etan Reisner
fuente
agregue más detalles sobre lo que hace su comando para que también sea útil para futuros lectores :)
Ramesh
1

@ inulinux12, puede usar el siguiente forbucle de una línea desde la línea de comandos:

$ for dir in images2/*; do mv "$dir"/* "${dir/2/}"; done

Esto moverá todos los archivos de images2a imagesen sus respectivos directorios. Nota: esto supone que ningún archivo tiene el mismo nombre.

Por ejemplo:

Antes de la ejecución:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2
images/adfoo:
jpg.7
images/fe:
jpg.5
images2:
ad  adfoo  fe
images2/ad:
jpg.3
images2/adfoo:
jpg.6
images2/fe:
jpg.4

Después de la ejecución:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2  jpg.3
images/adfoo:
jpg.6  jpg.7
images/fe:
jpg.4  jpg.5
Simplemente yo
fuente
3
No analice la salida de ls. mywiki.wooledge.org/ParsingLs
Etan Reisner
@EtanReisner Gracias por la sugerencia; Parece escenarios bastante estrechos, dada la información dada en la pregunta.
Simply_Me
2
@Simply_Me Si bien es cierto que generalmente estará bien, realmente no quieres que explote cuando golpees un caso con el que no contabas. Puede causar problemas realmente malos. Sin mencionar que con bastante frecuencia (como en este caso) es casi trivialmente reemplazable con un simple globo. Vea mi respuesta como un ejemplo de eso.
Etan Reisner
@Simply_Me Los escenarios incluyen nombres de archivos con espacios, lo cual es bastante común para las imágenes.
Gilles
@Gilles y @Etan Reisner, gracias por el aporte, ¡lo agradezco! Actualicé y probé mi respuesta para usar la sustitución de cadenas, y llegó a ser más rápido que usar basenameen esta situación particular (no es necesario llamar basenamepara esto). Gracias de nuevo por los comentarios constructivos.
Simply_Me