Qu'est-ce qui est plus efficace pour rechercher quels fichiers d'un système de fichiers entier contiennent une chaîne: grep récursif ou rechercher avec grep dans une instruction exec? Je suppose que find serait plus efficace car vous pouvez au moins faire un filtrage si vous connaissez l'extension de fichier ou une expression rationnelle qui correspond au nom du fichier, mais quand vous savez seulement -type f
qui est le meilleur? GNU grep 2.6.3; find (GNU findutils) 4.4.2
Exemple:
grep -r -i 'the brown dog' /
find / -type f -exec grep -i 'the brown dog' {} \;
-exec {} +
formulaire fera moins de forks, devrait donc être plus rapide que-exec {} \;
. Vous devrez peut-être ajouter-H
(ou-h
) auxgrep
options pour obtenir une sortie exactement équivalente.-r
option soit activéegrep
pour le secondRéponses:
Je ne suis pas sûr:
c'est vraiment ce que vous vouliez dire. Cela signifierait que grep récursivement dans tous les fichiers et répertoires non cachés de
/
(mais qu'il faut tout de même regarder à l'intérieur des fichiers et des répertoires cachés).En supposant que vous vouliez dire:
Quelques points à noter:
grep
implémentations ne prennent pas en charge-r
. Et parmi ceux qui le font, les comportements diffèrent: certains suivent les liens symboliques vers des répertoires lorsqu’ils parcourent l’arborescence (ce qui signifie que vous pouvez chercher plusieurs fois dans le même fichier ou même exécuter des boucles infinies), d’autres ne le feront pas. Certains vont regarder à l'intérieur des fichiers de périphériques (cela prendra un certain temps,/dev/zero
par exemple), des pipes ou des fichiers binaires ..., d'autres pas.grep
commence à regarder à l'intérieur des fichiers dès qu'il les découvre. Mais alors qu'il cherche dans un fichier, il ne cherche plus de fichiers dans lesquels chercher (ce qui est probablement aussi bien dans la plupart des cas)Votre:
(supprimé le
-r
qui n'a pas de sens ici) est terriblement inefficace parce que vous en exécutez ungrep
par fichier.;
ne devrait être utilisé que pour les commandes qui n'acceptent qu'un seul argument. De plus ici, comme ilgrep
ne regarde que dans un seul fichier, le nom du fichier ne sera pas imprimé, vous ne saurez pas où se trouvent les correspondances.Vous ne regardez pas dans les fichiers de périphérique, les pipes, les liens symboliques ..., vous ne suivez pas les liens symboliques, mais vous recherchez toujours des éléments tels que
/proc/mem
.serait beaucoup mieux parce que le moins de
grep
commandes possible serait exécuté. Vous obtiendrez le nom du fichier à moins que la dernière exécution ne comporte qu'un seul fichier. Pour cela, il vaut mieux utiliser:ou avec GNU
grep
:Notez que
grep
cela ne sera pas démarré avant d'find
avoir trouvé suffisamment de fichiers pour qu'il puisse être mâché, il y aura donc un délai initial. Etfind
ne poursuivra pas la recherche d'autres fichiers tant que le précédentgrep
n'est pas revenu. L'attribution et le passage de la liste des gros fichiers ont un impact (probablement négligeable), donc dans l'ensemble, cela sera probablement moins efficace qu'ungrep -r
lien qui ne suit pas un lien symbolique ou ne regarde pas à l'intérieur des périphériques.Avec les outils GNU:
Comme ci-dessus, le moins d’
grep
instances possibles seront exécutées, maisfind
continueront à rechercher davantage de fichiers pendant que la premièregrep
invocation est effectuée à l’intérieur du premier lot. Cela peut ou peut ne pas être un avantage si. Par exemple, avec des données stockées sur les disques durs de rotation,find
et l'grep
accès aux données stockées à différents endroits sur le disque va ralentir le débit du disque en provoquant la tête du disque de se déplacer en permanence. Dans une configuration RAID (oùfind
etgrep
peut accéder à différents disques) ou sur des SSD, cela peut faire une différence positive.Dans une configuration RAID, l'exécution de plusieurs appels simultanés
grep
peut également améliorer les choses. Toujours avec des outils GNU sur un stockage RAID1 avec 3 disques,pourrait augmenter la performance de manière significative. Notez cependant que le second
grep
ne sera démarré que lorsque suffisamment de fichiers auront été trouvés pour remplir la premièregrep
commande. Vous pouvez ajouter une-n
option àxargs
pour que cela se produise plus tôt (et transmettre moins de fichiers pargrep
appel).Notez également que si vous redirigez la
xargs
sortie vers un périphérique autre qu'un terminal, legreps
s commencera à mettre en tampon leur sortie, ce qui signifie que la sortie de cesgrep
s sera probablement mal entrelacée. Vous devriez les utiliserstdbuf -oL
(là où ils sont disponibles, comme sur GNU ou FreeBSD) pour résoudre ce problème (vous pouvez toujours rencontrer des problèmes avec de très longues lignes (généralement> 4 Ko)) ou demandez à chacun d’écrire leur sortie dans un fichier séparé et de les concaténer. tout à la fin.Ici, la chaîne que vous recherchez est fixe (pas une expression rationnelle), donc l'utilisation de l'
-F
option pourrait faire la différence (peu probable que lesgrep
implémentations sachent déjà l'optimiser).Une autre chose qui pourrait faire une grande différence est de fixer les paramètres régionaux sur C si vous êtes dans des paramètres régionaux multi-octets:
Pour éviter de regarder à l'intérieur
/proc
,/sys
..., utilisez-xdev
et spécifiez les systèmes de fichiers dans lesquels vous souhaitez effectuer la recherche:Ou élaguez les chemins que vous souhaitez exclure explicitement:
la source
-exec
prédicat dans la page de manuel SolarisSi l' appel
*
dans l'grep
appel n'est pas important pour vous, alors le premier devrait être plus efficace, car une seule instance degrep
est démarrée et les forks ne sont pas gratuits. Dans la plupart des cas, le traitement sera plus rapide, même dans les*
cas extrêmes, mais le tri pourrait inverser la tendance.Il peut y avoir d’autres
find
-grep
structures qui fonctionnent mieux, surtout avec beaucoup de petits fichiers. La lecture simultanée de grandes quantités d’entrées de fichier et d’inodes peut améliorer les performances des supports en rotation.Mais regardons les statistiques d'appels système:
trouver
seulement grep
la source
-r
indicateur degrep
lors de l'utilisationfind
. Vous pouvez voir qu'il a recherché à plusieurs reprises les mêmes fichiers en comparant le nombre deopen
ces événements.-r
devrait être inoffensif puisque la-type f
garantie ne contient aucun argument, ce sont des répertoires. Les multiplesopen()
s sont plus probablement liés aux autres fichiers ouverts pargrep
chaque invocation (bibliothèques, données de localisation ...) (merci pour l'édition sur ma réponse d'ailleurs)Si vous êtes sur un SSD et que le temps est compté, vous pouvez utiliser GNU parallel:
Ceci exécutera jusqu'à 8 processus grep en même temps en fonction de ce qui a été
find
trouvé.Cela écrasera un disque dur, mais un disque SSD devrait le supporter assez bien.
la source
Une dernière chose à considérer sur celui-ci est la suivante.
Est-ce que l'un des répertoires que grep devra parcourir de manière récursive contiendra plus de fichiers que le paramètre nofile de votre système ? (par exemple, nombre de descripteurs de fichiers ouverts, la valeur par défaut est 1024 sur la plupart des distributions Linux)
Si tel est le cas, alors find est le choix à faire, car certaines versions de grep génèreront une erreur de liste d'arguments trop longue quand un répertoire contenant plus de fichiers que le nombre maximal de fichiers ouverts a été défini.
Juste mon 2.
la source
grep
bombarder? Au moins avec GNU grep, si vous indiquez un chemin avec une fin/
et que vous l’utilisez,-R
il vous suffira de parcourir les répertoires. Le shell ne développera rien à moins que vous ne donniez des shell-globs. Ainsi, dans l'exemple donné (/*
), seul le contenu de la/
matière, pas celui des sous-dossiers qui seront simplement énumérésgrep
, et non transmis comme argument à partir du shell.