Moyen le plus rapide de concaténer des fichiers

25

J'ai 10k + fichiers totalisant plus de 20 Go que je dois concaténer en un seul fichier.

Y a-t-il un moyen plus rapide que

cat input_file* >> out

?

La manière préférée serait une commande bash, Python est également acceptable sinon considérablement plus lent.

fsperrle
la source
Mis à jour ma réponse, findne trie pas les fichiers de la même manière qu'un shell glob.
Graeme
5
Toutes les solutions (saines) auront une vitesse équivalente ici car le temps sera de 99% d'E / S système.
goldilocks
3
Envisager d'écrire le fichier concaténé sur un disque différent de celui que vous lisez.
Luis
1
Il sera plus rapide s'il outse trouve sur un autre disque.

Réponses:

30

Non, le chat est sûrement le meilleur moyen de le faire. Pourquoi utiliser python alors qu'il existe un programme déjà écrit en C à cet effet? Cependant, vous pouvez toutefois envisager d'utiliser xargsau cas où la longueur de la ligne de commande dépasse ARG_MAXet que vous en avez besoin de plusieurs cat. En utilisant des outils GNU, cela équivaut à ce que vous avez déjà:

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z |
  xargs -0 cat -- >>out
Graeme
la source
1
Pouvez-vous assurer dans ce cas que vos fichiers seront lus dans l'ordre?
Kiwy
1
Oui, car la sortie de findest acheminée sort. Sans cela, les fichiers seraient répertoriés dans un ordre arbitraire (défini par le système de fichiers, qui pourrait être un ordre de création de fichiers).
scai
@scai J'ai mal lu désolé, avec le tri c'est assez évident
Kiwy
1
@Kiwy, le seul cas que je peux voir est que si les paramètres régionaux ne sont pas correctement définis dans l'environnement, alors le tri pourrait se comporter différemment d'un bashglob. Sinon, je ne vois aucun cas où xargsou catne se comporterait pas comme prévu.
Graeme
3
@MarcvanLeeuwen, xargsappellera autant catque nécessaire pour éviter une erreur E2BIG de execve (2).
Stéphane Chazelas
21

L'allocation de l'espace pour le fichier de sortie en premier peut améliorer la vitesse globale car le système n'aura pas à mettre à jour l'allocation pour chaque écriture.

Par exemple, si sous 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

Un autre avantage est que s'il n'y a pas assez d'espace libre, la copie ne sera pas tentée.

Si cette option est activée btrfs, vous pouvez créer copy --reflink=alwaysle premier fichier (ce qui n'implique aucune copie de données et serait donc presque instantané) et ajouter le reste. S'il y a 10000 fichiers, cela ne fera probablement pas beaucoup de différence, sauf si le premier fichier est très volumineux.

Il y a une API pour généraliser cela pour recopier tous les fichiers (les BTRFS_IOC_CLONE_RANGE ioctl), mais je n'ai trouvé aucun utilitaire exposant cette API, vous devriez donc le faire en C ( pythonou dans d'autres langues à condition qu'ils puissent appeler des ioctls arbitraires ) .

Si les fichiers source sont clairsemés ou ont de grandes séquences de caractères NUL, vous pouvez créer un fichier de sortie clairsemé (gain de temps et d'espace disque) avec (sur les systèmes GNU):

find . -maxdepth 1 -type f -name 'input_file*' -print0 |
  sort -z | xargs -r0 cat | cp --sparse=always /dev/stdin out
Stéphane Chazelas
la source
1
@XTian, ​​non, cela ne devrait être ni >ni >>, mais 1<>comme je l'ai dit, écrire dans le fichier.
Stéphane Chazelas
5
@grebneke, <>est l'opérateur de redirection de lecture / écriture Bourne / POSIX standard. Consultez le manuel de votre shell ou la spécification POSIX pour plus de détails. La valeur par défaut fdest 0pour l' <>opérateur ( <>est court pour 0<>, comme <est court pour 0<et >court pour 1>), vous avez donc besoin de 1pour rediriger explicitement stdout. Ici, ce n'est pas tellement que nous avons besoin de read + write ( O_RDWR), mais que nous ne voulons pas O_TRUNC(comme dans >) qui désallouerait ce que nous venons d'allouer.
Stéphane Chazelas
1
@grebneke, unix.stackexchange.com/search?q=user%3A22565+%22%3C%3E%22 vous en donnera quelques-uns. ksh93 a des opérateurs de recherche BTW, et vous pouvez rechercher en avant avec ddou via la lecture.
Stéphane Chazelas
1
@StephaneChazelas - merci beaucoup, votre aide et vos connaissances sont profondément appréciées!
grebneke
1
Je ne suis pas convaincu qu'il y aura de nombreux cas où fallocateles frais généraux seront annulés find, même si ce sera plus rapide la deuxième fois. btrfsouvre certainement des possibilités intéressantes.
Graeme