La forma más rápida de concatenar archivos

25

Tengo más de 10k archivos por un total de más de 20GB que necesito concatenar en un solo archivo.

¿Hay una manera más rápida que

cat input_file* >> out

?

La forma preferida sería un comando bash, Python también es aceptable si no considerablemente más lento.

fsperrle
fuente
Actualicé mi respuesta, findno clasifica los archivos de la misma manera que un shell glob.
Graeme
55
Todas y cada una de las soluciones (sanas) tendrán una velocidad equivalente aquí, ya que el tiempo será del 99% de E / S del sistema.
Ricitos de Oro
3
Considere escribir el archivo concatenado en un disco diferente del que está leyendo.
Luis
1
Será más rápido si outse encuentra en otro disco.

Respuestas:

30

No, el gato es seguramente la mejor manera de hacer esto. ¿Por qué usar python cuando ya hay un programa escrito en C para este propósito? Sin embargo, es posible que desee considerar el uso xargsen caso de que la longitud de la línea de comando exceda ARG_MAXy necesite más de uno cat. Usando herramientas GNU, esto es equivalente a lo que ya tiene:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out
Graeme
fuente
1
¿Puede asegurar en este caso que sus archivos se leerán en el orden?
Kiwy
1
Sí, porque la salida de findse canaliza sort. Sin esto, los archivos se enumerarían en un orden arbitrario (definido por el sistema de archivos, que podría ser el orden de creación de archivos).
scai
@scai Lo he leído mal, lo siento, es bastante obvio
Kiwy 05 de
1
@Kiwy, el único caso que puedo ver es si la configuración regional no está configurada correctamente en el entorno, entonces la ordenación podría comportarse de manera diferente a un bashglobo. De lo contrario, no veo ningún caso donde xargso catno se comportaría como se esperaba.
Graeme
3
@MarcvanLeeuwen, xargsllamará lo más que pueda catpara evitar un error E2BIG de execve (2).
Stéphane Chazelas
21

Asignar primero el espacio para el archivo de salida puede mejorar la velocidad general ya que el sistema no tendrá que actualizar la asignación para cada escritura.

Por ejemplo, si en Linux:

size=$({ find . -maxdepth 1 -type f -name 'input_file*' -printf '%s+'; echo 0;} | bc)
fallocate -l "$size" out &&
  find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat 1<> out

Otro beneficio es que si no hay suficiente espacio libre, la copia no se intentará.

Si está activado btrfs, podría copy --reflink=alwaysel primer archivo (lo que implica que no hay copia de datos y, por lo tanto, sería casi instantáneo), y agregar el resto. Si hay 10000 archivos, eso probablemente no hará mucha diferencia, a menos que el primer archivo sea muy grande.

Hay una API para generalizar eso para volver a copiar todos los archivos (the BTRFS_IOC_CLONE_RANGE ioctl), pero no pude encontrar ninguna utilidad que exponga esa API, por lo que tendrías que hacerlo en C ( pythonu otros lenguajes siempre que puedan llamar ioctls arbitrarios ) .

Si los archivos de origen son escasos o tienen secuencias grandes de caracteres NUL, puede crear un archivo de salida disperso (ahorrando tiempo y espacio en disco) con (en sistemas GNU):

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
Stéphane Chazelas
fuente
1
@XTian, ​​no, no debería ser ni >ni >>, pero 1<>como dije escribir en el archivo.
Stéphane Chazelas
55
@grebneke, <>es el operador estándar de redirección de lectura + escritura Bourne / POSIX. Consulte su manual de shell o la especificación POSIX para más detalles. El valor predeterminado fdes 0para el <>operador ( <>es corto para 0<>, como <es corto para 0<y >corto para 1>), por lo que necesita 1redireccionar explícitamente stdout. Aquí, no es tanto que necesitemos leer + escribir ( O_RDWR), sino que no queremos O_TRUNC(como en >) lo que desasignaría lo que acabamos de asignar.
Stéphane Chazelas
1
@grebneke, unix.stackexchange.com/search?q=user%3A22565+%22%3C%3E%22 le dará algunos. ksh93 tiene operadores de búsqueda, por cierto, y puede buscar hacia adelante con ddo mediante la lectura.
Stéphane Chazelas
1
@StephaneChazelas: ¡muchas gracias, su ayuda y conocimiento son muy apreciados!
grebneke
1
No estoy convencido de que haya muchos casos en los fallocateque negará la sobrecarga del extra find, aunque será más rápido la segunda vez. btrfsSin embargo, sin duda abre algunas posibilidades interesantes.
Graeme