
Quiero mover archivos de más de "300 MB" de un árbol de directorios donde cada archivo se encuentra en subcarpetas
Ejemplo: tengo una estructura de directorios:
dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3
Este es el resultado esperado, un "mover" del árbol de directorios donde cada archivo se mueve a las subcarpetas:
dirB/ # normal directory
dirB/file1 # moved from dirA/file1
dirB/x/ # normal directory
dirB/x/file2 # moved from dirA/x/file2
dirB/y/ # normal directory
dirB/y/file3 # moved from dirA/y/file3
¿ find /path/ -type f -size +300m
Pero luego qué? y desafortunadamente algunos de los archivos tienen todo tipo de caracteres que puedes encontrar en tu teclado.
he estado mirando estohilodonde alguien habla cpio
pero no conozco ese programa...
PD: ¿Tiene GNU Parallel instalado si esto pudiera acelerar las cosas?
Respuesta1
La manera fácil es conzsh. Puedes usarclasificatorios globalespara unir archivos según criterios como su tipo y tamaño. Elpatrón comodín **/
coincide con cualquier nivel de subdirectorios. Elmodificadores de historia h
y t
son formas sencillas de extraer el directorio y la parte base de un nombre de archivo. Llame mkdir -p
para crear los directorios cuando sea necesario.
cd dirA
for x in **/*(.Lm+300); do
mkdir -p ../dirB/$x:h &&
mv -- $x ../dirB/$x
done
La forma portátil es con find
. Úselo -exec
para invocar un fragmento de shell para cada archivo.
cd dirA
find . -type f -size +300000k -exec sh -c 'for x do
mkdir -p "../dirB/${x%/*}"
mv "$x" "../dirB/$x"
done' sh {} +
La paralelización rara vez es útil para la entrada/salida: le permite aprovechar múltiples CPU, pero la CPU rara vez es un cuello de botella en la E/S.
Respuesta2
Perl rename
es la elección obvia. Puede instalarse como ren
, rename
o pren
:
find dirA -type f -size +300M | ren 's:^dirA/:dirB/:'
Sin embargo, no funciona si los archivos se mueven a un punto de montaje diferente y fallará si los directorios no están allí.
GNU Parallel será más lento:
cd dirA
find . -type f -size +300M | parallel mkdir -p ../dirB/{//}
find . -type f -size +300M | parallel mv {} ../dirB/{}
pero funcionará incluso si necesita realizar la rutina de copiar y luego eliminar para colocar los archivos en un sistema de archivos diferente.
Respuesta3
En breve:
find dirA -type f -size +300m -printf "mv %p dirB/%P\n" | sh
Pero todos los subdirectorios en dirB deben existir antes de comenzar. Por esta razón te sugiero que sigas los siguientes dos pasos:
cd dirA
find . -type f -size +300m -printf "mkdir -p ../dirB/%h\nmv %p ../dirB/%P\n" | sh
Respecto a cpio (en realidad resuelve el problema de los subdirectorios):
(cd dirA; find . -type f -size +300m) | cpio -p -md dirB
(Con respecto al cp(1) en el mismo hilo que mencionas, no es bueno para ti, porque copiará todo Los archivos y cree un subdirectorio llamado dirA en dirB. La bandera-Tpuede resolver este problema)
Respuesta4
Esto debería cubrirlo.
find /path -type f -size +300m | while read A ; do DEST=${A/dirA/dirB} ; echo mkdir -p $(dirname $DEST) 2>/dev/null; echo mv $A $DEST ; done
Primero ejecútelo como está, verifique su integridad y, si está satisfecho con los comandos propuestos, vuelva a ejecutarlo sin los echo
elementos.
En su ejemplo de estructura de archivos, generaría los siguientes comandos
mkdir -p ./dirB
mv ./dirA/file1 ./dirB/file1
mkdir -p ./dirB/x
mv ./dirA/x/file2 ./dirB/x/file2
mkdir -p ./dirB/y
mv ./dirA/y/file3 ./dirB/y/file3