Quiero paralelizar la división de muchos directorios en subdirectorios usando parallel
o usando otra herramienta o método.
Por ejemplo, tengo 1.000.000 de directorios con contenido, pero es demasiado para un directorio, por lo que quiero crear 10 directorios en el directorio principal y mover en cada uno de ellos 100.000 directorios originales. También quiero utilizar la clasificación por fecha. Ya preguntépregunta similar aquí, pero esto no está duplicado, porque probé nuevos comandos, obtuve nuevos resultados y ahora reformulé la pregunta.
Entonces ya probé esto
ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}"
y esto
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
comandos, pero mueve solo ~ 10 000 a un subdirectorio (a veces ~ 6200, a veces ~ 12 500) y crea demasiados subdirectorios, a veces 10 veces más de lo que necesito.
También intenté usar esto:
ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
pero dio bash: /bin/ls: Argument list too long
.
Por supuesto, no necesito exactamente 100 000 directorios en cada subdirectorio, pueden ser 101 000 o 98 500 directorios, debería ser un número en el rango de 100 000.
¿Cómo puedo ejecutar esta tarea en paralelo o usando parallel
?
Respuesta1
El problema es que hay un límite superior de bytes que una línea de comando puede tomar después de la expansión del shell, este límite depende del límite del sistema.
getconf ARG_MAX
lo que hace que el número de argumentos mv {}
varíe dependiendo de la longitud del nombre del archivo de entrada cada vez que alcance el límite máximo.
Una solución para evitar este límite sin renunciar al uso paralelo es dividir la tarea en dos etapas.
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
Explicación
La primera etapa utiliza la opción
--pipe
de dividir la entrada estándar en un número determinado deentradas estándar más pequeñas, cada uno de los cuales contiene n líneas según lo especificado por la opción-N
. Puedes observar el efecto usando este ejemplo.seq 1000000 | parallel -N 100000 --pipe wc -l
lo que da una división exacta en la marca de 100000
100000 100000 100000 ...
En la segunda etapa, los paralelos interiores toman elentradas estándar más pequeñascomo su nueva entrada estándar para ejecutar sus trabajos, la
-X
opción inserta tantos argumentos como lo permita la longitud de la línea de comandomkdir dir_{#}; parallel -X mv -t dir_{#}
Respuesta2
Este problema se refiere a IO intensas. Dudo que parallel
sea realmente útil en esta situación.
De todos modos te sugiero que consideres un enfoque "tradicional":
mkdir dir_{1..10}
ls -tr | nl | \
awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'
dónde
ls -tr | nl
ordena los directorios por fecha y agrega un número de directorio auxiliar$2 !~ /^dir_/
se utiliza para omitir las carpetas recién creadas.i=1+int($1/100000)
calcula el número de la carpeta en función del número de directorioprint $2 | "xargs mv -t dir_"i
se mueve sin proliferación de procesos
Si es posible compara también los tiempos respectivos: time ....
(y comparte los resultados con nosotros ☺)