Cómo mover un archivo de forma recursiva según el tamaño y mantener la estructura

Cómo mover un archivo de forma recursiva según el tamaño y mantener la estructura

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 +300mPero 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 cpiopero 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 hy tson formas sencillas de extraer el directorio y la parte base de un nombre de archivo. Llame mkdir -ppara 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 -execpara 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 renamees la elección obvia. Puede instalarse como ren, renameo 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 echoelementos.

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

información relacionada