J'ai un répertoire contenant 10144911 fichiers. Jusqu'à présent, j'ai essayé ce qui suit:
for f in ls; do sed -i -e 's/blah/blee/g' $f; done
J'ai cassé ma coquille, ls
c'est dans un tilda mais je ne sais pas comment en faire un.
ls | xargs -0 sed -i -e 's/blah/blee/g'
Trop d'arguments pour sed
find . -name "*.txt" -exec sed -i -e 's/blah/blee/g' {} \;
Impossible de bifurquer plus de mémoire
Avez-vous d'autres idées sur la façon de créer cette sorte de commande? Les fichiers n'ont pas besoin de communiquer entre eux. ls | wc -l
semble fonctionner (très lentement) donc ça doit être possible.
sed
pour chaque fichier. Je ne sais pas s'il existe un moyen d'ouvrir, de modifier, d'enregistrer et de fermer une série de fichierssed
; si la vitesse est essentielle, vous voudrez peut-être utiliser un programme différent, peut-être perl ou python.sed
est probablement plus rapide que le lancementpython
ouperl
aussi, sauf si vous faites tout dans cet interpréteur.Réponses:
Essayez ceci:
Il ne fournira qu'un seul nom de fichier à chaque invocation de
sed
. Cela résoudra le problème «trop d'arguments pour sed». L'-P
option doit permettre à plusieurs processus d'être bifurqués en même temps. Si 0 ne fonctionne pas (il est censé en exécuter autant que possible), essayez d'autres nombres (10? 100? Le nombre de cœurs que vous avez?) Pour limiter le nombre.la source
find . -name \*.txt -print0
éviter que le shell n'élargisse le glob et ne tente d'allouer de l'espace pour 10 millions d'arguments à trouver .J'ai testé cette méthode (et toutes les autres) sur 10 millions de fichiers (vides), nommés "hello 00000001" à "hello 10000000" (14 octets par nom).
MISE À JOUR: J'ai maintenant inclus une exécution quad-core sur la
'find |xargs'
méthode (toujours sans 'sed'; juste echo> / dev / null) ..Voici un résumé de la façon dont les réponses fournies se sont comportées lorsqu'elles ont été comparées aux données de test mentionnées ci-dessus. Ces résultats ne concernent que les frais généraux de base; c'est-à-dire que «sed» n'a pas été appelé. Le processus sed sera certainement le plus long, mais j'ai pensé qu'il serait intéressant de voir comment les méthodes nues se comparaient.
La
'find |xargs'
méthode de Dennis , utilisant un seul cœur, a pris * 4 heures 21 minutes ** de plus que labash array
méthode lors d'une analyseno sed
... Cependant, l'avantage multicœur offert par 'find' devrait l'emporter sur les différences de temps indiquées lorsque sed est demandé. traitement des fichiers ...la source
Une autre opportunité pour la découverte complètement sûre :
la source
Ceci est principalement hors sujet, mais vous pouvez utiliser
Le principal avantage ici (sur
... xargs ... -I {} ... sed ...
) est la vitesse: vous évitez d'invoquersed
10 millions de fois. Ce serait encore plus rapide si vous pouviez éviter d'utiliser Python (car python est un peu lent, relativement), donc perl pourrait être un meilleur choix pour cette tâche. Je ne sais pas comment faire l'équivalent facilement avec perl.La façon dont cela fonctionne est d'
xargs
invoquer Python avec autant d'arguments qu'il peut tenir sur une seule ligne de commande, et de continuer ainsi jusqu'à épuisement des arguments (fournis parls -f *.txt
). Le nombre d'arguments pour chaque invocation dépendra de la longueur des noms de fichiers et, euh, d'autres éléments. Lafileinput.input
fonction génère des lignes successives à partir des fichiers nommés dans les arguments de chaque invocation, et l'inplace
option lui dit de "capturer" par magie la sortie et de l'utiliser pour remplacer chaque ligne.Notez que la
replace
méthode de chaîne de Python n'utilise pas de regexps; si vous en avez besoin, vous devez lesimport re
utiliserprint re.sub(line, "blah", "blee")
. Ce sont des RegExps compatibles Perl, qui sont en quelque sorte des versions fortement enrichies de celles que vous obtenezsed -r
.Éditer
Comme le mentionne akira dans les commentaires, la version originale utilisant un glob (
ls -f *.txt
) à la place de lafind
commande ne fonctionnerait pas car les globs sont traités par le shell (bash
) lui-même. Cela signifie qu'avant même l'exécution de la commande, 10 millions de noms de fichiers seront substitués dans la ligne de commande. Il est à peu près garanti de dépasser la taille maximale de la liste d'arguments d'une commande. Vous pouvez utiliserxargs --show-limits
pour des informations spécifiques au système à ce sujet.La taille maximale de la liste d'arguments est également prise en compte par
xargs
, ce qui limite le nombre d'arguments qu'elle passe à chaque appel de python en fonction de cette limite. Comme ilxargs
faudra encore invoquer python plusieurs fois, la suggestion d'Akira d'utiliseros.path.walk
pour obtenir la liste des fichiers vous fera probablement gagner du temps.la source
os.path.walk()
?.
et..
. Il y a certainement d'autres façons de le faire (c'est-à-direfind
), mais j'essaie de m'en tenir le plus possible à ce que l'OP comprend. C'est aussi la raison de ne pas utiliseros.path.walk
.os.path.walk
assez facilement.Essayer:
la source
ls -f
serait mieux; voulez-vous vraiment attendrestat()
et trier autant de fichiers?