
Tengo dos directorios que deben fusionarse. Los archivos de estos dos directorios son todos archivos grandes (>= 500 MB).
Lo que quiero archivar: Para archivos en el directorio de origen: si no existe en el directorio de destino, mv
en el directorio de destino (lo cual es rápido ya que básicamente estamos creando un nuevo vínculo físico y desvinculando el archivo de origen); si existe en el directorio de destino, copie el archivo fuente allí y elimine el archivo fuente.
La forma más común de fusionar directorios en el sistema Linux es utilizar la opción rsync
with --remove-source-files
. Pero esto es lento porque realizará la operación de copia incluso si el archivo de destino no existe.
¿Alguna idea mejor? Gracias.
Respuesta1
Básicamente, lo que describiste es mover archivos a un destino de sobrescritura si existe. Así que muévelos.
Respuesta2
Hay un caso en el que mv
falla. A continuación se muestran algunos datos de ejemplo:
mkdir -p src/d dest/d
touch src/d/f1 dest/d/f2
Mira cómo mv
falla:
$ mv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -f src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fv src/* dest/
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi src/* dest/
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
$ mv -fvi -t dest/ src/*
mv: overwrite 'dest/d'? y
mv: cannot move 'src/d' to 'dest/d': Directory not empty
Así que crea un archivo de script:
vim supermove
Este ejemplo no realiza verificación de errores (DESCARGO DE RESPONSABILIDAD: funciona para mí, pero pruebe que funcione para usted... tal vez con echo
before mv
) y sobrescribirá los archivos con la misma ruta. Y utiliza buscar con \;
lo cual es terriblemente ineficiente, pero +
no funciona bien con "$dest"
antepuesto. Las versiones anteriores crearán algunos directorios sin la ruta antepuesta, y las versiones más nuevas de buscar dirán:
find: In '-exec ... {} +' the '{}' must appear by itself, but you specified 'dest/{}'
Sin embargo, probablemente puedas encontrar una manera de solucionarlo con xargs. (Me tomó unos minutos en los archivos de 64k y 8TB que estaba moviendo). Añade este contenido:
#!/bin/bash
src=$1
dest=$2
src=$(readlink -f "$src")
dest=$(readlink -f "$dest")
cd "$src"
# also copy hidden files
shopt -s dotglob
# make dirs (missing old permission,acl,xattr data), and then mv the files
time find * -type d -exec mkdir -p "$dest"/{} \;
time find * -type f -exec mv {} "$dest"/{} \;
# also copy permissions, acls, xattrs
rsync -aAX "$src"/ "$dest"/
Y hacerlo ejecutable:
chmod +rx supermove
y ejecutarlo
./supermove src/ dest/
Y el resultado... antes:
$ find src dest
src/
src/d
src/d/f1
dest/
dest/d
dest/d/f2
Después:
$ find src dest
src
src/d
dest
dest/d
dest/d/f1
dest/d/f2
Ahora src/
deberían quedar solo directorios vacíos. Si es así, puedes rm -r src
limpiarlo.
Respuesta3
mv
Las opciones tienen que ver con la resolución de conflictos:
Elegir uno:
-f force (always overwrite)
-i interactive (ask whether to overwrite)
-n no clobber (no overwrite)
Y esto también es bueno:
-v verbose
De lo contrario, los datos pueden perderse y/o no quedará claro qué sucedió exactamente.
mv también es superior en el mismo fs porque solo actualiza los inodos del directorio, no se deben alterar los archivos. La otra cosa es que cuanto mayor sea la operación, mayor será la posibilidad de que algo salga mal, como errores leves.