J'ai ± 10 000 fichiers ( res.1
- res.10000
) tous constitués d'une colonne et d'un nombre égal de lignes. Ce que je veux est, par essence, simple; fusionner tous les fichiers colonne par colonne dans un nouveau fichier final.res
. J'ai essayé d'utiliser:
paste res.*
Cependant (bien que cela semble fonctionner pour un petit sous - ensemble de fichiers de résultats, cela donne l'erreur suivante lorsqu'elle est effectuée sur l'ensemble: Too many open files
.
Il doit y avoir un moyen «facile» de faire cela, mais malheureusement je suis assez nouveau pour unix. Merci d'avance!
PS: Pour vous donner une idée de ce à quoi (un de mes) fichiers de données ressemble:
0.5
0.5
0.03825
0.5
10211.0457
10227.8469
-5102.5228
0.0742
3.0944
...
--serial
option avec lapaste
commande?paste --serial
ne fusionne pas les fichiers colonne par colonne ...paste -s
fonctionne en effet, mais colle les fichiers de résultats séparés en ligne plutôt qu'en colonne. Cependant, c'est quelque chose que je peux résoudre. Merci!Réponses:
Si vous avez des autorisations root sur cette machine, vous pouvez augmenter temporairement la limite du "nombre maximum de descripteurs de fichiers ouverts":
Puis
Après cela, vous pouvez rétablir les valeurs d'origine.
Une deuxième solution , si vous ne pouvez pas modifier la limite:
Il appelle
paste
chaque fichier une fois, et à la fin il y a un énorme fichier avec toutes les colonnes (cela prend sa minute).Edit : Utilisation inutile du chat ... Non !
Comme mentionné dans les commentaires, l'utilisation de
cat
here (cat final.res | paste - $f >temp
) n'est pas inutile. La première fois que la boucle s'exécute, le fichierfinal.res
n'existe pas déjà.paste
échouerait alors et le fichier n'est jamais rempli, ni créé. Avec ma solutioncat
échoue seulement la première fois avecNo such file or directory
etpaste
lit depuis stdin juste un fichier vide, mais il continue. L'erreur peut être ignorée.la source
ulimit -Sn
pour la limite douce etulimit -Hn
pour la limite dure-bash: /usr/bin/paste: Argument list too long
. Des idées pour résoudre ce problème? Désolé de vous déranger les gars.getconf ARG_MAX
, vous ne pouvez augmenter cette valeur que lors de la recompilation du noyau. Vous pouvez essayer ma deuxième solution?cat
chaque fois la boucle, vous pouvez commencer par créer unfinal.res
fichier vide . C'est probablement une bonne idée de toute façon, au cas où il y aurait déjà unfinal.res
fichier.Si la réponse du chaos n'est pas applicable (car vous ne disposez pas des autorisations requises), vous pouvez regrouper les
paste
appels comme suit:Cela répertorie les fichiers 1000 à la fois dans des fichiers nommés
lists00
,lists01
etc., puis colle lesres.
fichiers correspondants dans des fichiers nommésmerge00
,merge01
etc., et fusionne finalement tous les fichiers partiellement fusionnés résultants.Comme mentionné par le chaos, vous pouvez augmenter le nombre de fichiers utilisés simultanément; la limite est la valeur indiquée
ulimit -n
moins le nombre de fichiers que vous avez déjà ouverts, vous diriez doncd'utiliser la limite moins dix.
Si votre version de
split
ne prend pas en charge-d
, vous pouvez la supprimer: il suffit de diresplit
d'utiliser des suffixes numériques. Par défaut, les suffixes serontaa
,ab
etc. au lieu de01
,02
etc.S'il y a tellement de fichiers qui
ls -1 res.*
échouent ("liste d'arguments trop longue"), vous pouvez le remplacer parfind
ce qui évitera cette erreur:(Comme indiqué par don_crissti , cela
-1
ne devrait pas être nécessaire lors dels
la sortie de la tuyauterie ; mais je le laisse pour gérer les cas oùls
est aliasé avec-C
.)la source
Essayez de l'exécuter de cette façon:
Vous pouvez également diviser le lot en plusieurs parties et essayer quelque chose comme:
et à la fin, combiner les fichiers finaux
la source
Too many open files
final.x00
canaux be - soit en tant que FIFO nommés, soit implicitement, en utilisant la substitution de processus (si votre shell le prend en charge - par exemple bash). Ce n'est pas amusant d'écrire à la main, mais pourrait bien convenir à un makefile.Je ne pense pas que ce soit aussi compliqué que cela - vous avez déjà fait le gros travail en commandant les noms de fichiers. Ne les ouvrez pas tous en même temps, c'est tout.
Autrement:
... mais je pense que cela les fait reculer ... Cela pourrait mieux fonctionner:
Et voici encore une autre façon:
Cela permet
tar
de rassembler pour vous tous les fichiers dans un flux délimité par des valeurs nulles, d'analyser toutes ses métadonnées d'en-tête sauf le nom de fichier et de transformer toutes les lignes de tous les fichiers en onglets. Il s'appuie cependant sur l'entrée comme étant des fichiers texte réels - ce qui signifie que chaque extrémité se termine par une nouvelle ligne et qu'il n'y a pas d'octets nuls dans les fichiers. Oh - et cela repose également sur le fait que les noms de fichiers eux-mêmes sont sans nouvelle ligne (bien que cela puisse être géré de manière robuste avectar
l'--xform
option GNU ) . Étant donné que ces conditions sont remplies, il devrait faire très peu de travail sur n'importe quel nombre de fichiers - ettar
fera presque tout.Le résultat est un ensemble de lignes qui ressemblent à:
Etc.
Je l'ai testé en créant d'abord 5 fichiers de test. Je n'avais pas vraiment envie de créer 10000 fichiers à l'instant, alors je suis juste allé un peu plus gros pour chacun - et j'ai également veillé à ce que la longueur des fichiers diffère considérablement. Ceci est important lors du test de
tar
scripts cartar
il bloquera l'entrée à des longueurs fixes - si vous n'essayez pas au moins quelques longueurs différentes, vous ne saurez jamais si vous ne gérerez réellement que celle-là.Quoi qu'il en soit, pour les fichiers de test, j'ai fait:
ls
a ensuite rapporté:... puis j'ai couru ...
... juste pour n'afficher que les 25 premiers champs délimités par tabulation par ligne (car chaque fichier est une seule ligne - il y en a beaucoup ) ...
Le résultat était:
la source
Compte tenu de la quantité de fichiers, de tailles de lignes, etc. impliqués, je pense que cela dépassera les tailles par défaut des outils (awk, sed, paste, *, etc.)
Je créerais un petit programme pour cela, il n'aurait ni 10 000 fichiers ouverts, ni une ligne de centaines de milliers de long (10 000 fichiers de 10 (taille max de ligne dans l'exemple)). Il ne nécessite qu'un ~ 10 000 tableau d'entiers, pour stocker le nombre d'octets lus dans chaque fichier. L'inconvénient est qu'il n'a qu'un seul descripteur de fichier, il est réutilisé pour chaque fichier, pour chaque ligne, et cela peut être lent.
Les définitions de
FILES
etROWS
doivent être remplacées par les valeurs exactes réelles. La sortie est envoyée à la sortie standard.la source