web-dev-qa-db-fra.com

Pourquoi la commande "find | grep 'filename'" est-elle tellement plus lente que "find 'filename'"?

J'ai essayé les deux commandes et la commande find | grep 'filename' est beaucoup plus lent que le simple find 'filename' commande.

Quelle serait une explication appropriée de ce comportement?

10
yoyo_fun

(Je suppose que GNU find ici)

En utilisant juste

find filename

serait rapide, car il retournerait simplement filename, ou les noms à l'intérieur filename s'il s'agit d'un répertoire, ou une erreur si ce nom n'existait pas dans le courant annuaire. C'est une opération très rapide, similaire à ls filename (mais récursif si filename est un répertoire).

En revanche,

find | grep filename

permettrait à find de générer une liste de tous noms à partir du répertoire courant et ci-dessous, que grep filtrerait ensuite. Ce serait évidemment une opération beaucoup plus lente.

Je suppose que ce qui était en fait prévu était

find . -type f -name 'filename'

Cela rechercherait filename comme nom d'un fichier normal n'importe où dans le répertoire courant ou en dessous.

Ce sera aussi rapide (ou comparable) que find | grep filename, mais la solution grep correspondrait à filename par rapport au chemin complet de chaque nom trouvé, de la même manière que -path '*filename*' ferait avec find.


La confusion vient d'une mauvaise compréhension du fonctionnement de find.

L'utilitaire prend un certain nombre de chemins et renvoie tous les noms sous ces chemins.

Vous pouvez alors restreindre les noms retournés en utilisant divers tests qui peuvent agir sur le nom de fichier, le chemin, l'horodatage, la taille du fichier, le type de fichier, etc.

Quand tu dis

find a b c

vous demandez à find de répertorier tous les noms disponibles sous les trois chemins a, b et c. S'il se trouve que ce sont des noms de fichiers normaux dans le répertoire courant, ils seront retournés. Si l'un d'eux se trouve être le nom d'un répertoire, il sera retourné avec tous les autres noms à l'intérieur de ce répertoire.

Quand je fais

find . -type f -name 'filename'

Cela génère une liste de tous les noms dans le répertoire courant (.) et plus bas. Ensuite, il restreint les noms à ceux des fichiers normaux, c'est-à-dire pas aux répertoires, etc., avec -type f. Ensuite, il existe une autre restriction aux noms qui correspond à filename à l'aide de -name 'filename'. La chaîne filename peut être un modèle de remplacement de nom de fichier, tel que *.txt (n'oubliez pas de le citer!).

Exemple:

Ce qui suit semble "trouver" le fichier appelé .profile dans mon répertoire personnel:

$ pwd
/home/kk
$ find .profile
.profile

Mais en fait, il renvoie juste tous les noms sur le chemin .profile (il n'y a qu'un seul nom, c'est celui de ce fichier).

Ensuite, je cd monte d'un niveau et réessaye:

$ cd ..
$ pwd
/home
$ find .profile
find: .profile: No such file or directory

La commande find ne peut plus trouver de chemin appelé .profile.

Cependant, si je le fais regarder le répertoire courant, puis restreindre les noms retournés à seulement .profile, il le trouve également à partir de là:

$ pwd
/home
$ find . -name '.profile'
./kk/.profile
11
Kusalananda

Explication non technique: rechercher Jack dans une foule est plus rapide que rechercher tout le monde dans une foule et éliminer tout de la considération sauf Jack.

2
S Renalds

Je n'ai pas encore compris le problème, mais je peux fournir quelques informations supplémentaires.

Comme pour Kusalananda, le find | grep l'appel est clairement plus rapide sur mon système, ce qui n'a pas beaucoup de sens. Au début, j'ai supposé une sorte de problème de mise en mémoire tampon; que l'écriture dans la console ralentit le temps jusqu'au prochain appel système pour lire le nom de fichier suivant. L'écriture sur un tube est très rapide: environ 40 Mo/s même pour des écritures de 32 octets (sur mon système plutôt lent; 300 Mo/s pour une taille de bloc de 1 Mo). J'ai donc supposé que find pouvait lire plus rapidement à partir du système de fichiers lors de l'écriture dans un canal (ou fichier) afin que les deux opérations de lecture des chemins de fichier et d'écriture dans la console puissent s'exécuter en parallèle (qui find comme un processus à un seul thread ne peut pas le faire seul.

C'est la faute de find

Comparaison des deux appels

:> time find "$HOME"/ -name '*.txt' >/dev/null

real    0m0.965s
user    0m0.532s
sys     0m0.423s

et

:> time find "$HOME"/ >/dev/null

real    0m0.653s
user    0m0.242s
sys     0m0.405s

montre que find fait quelque chose d'incroyablement stupide (quoi que ce soit). Il s'avère juste être assez incompétent pour exécuter -name '*.txt'.

Peut dépendre du rapport entrée/sortie

Vous pourriez penser que find -name gagne s'il y a très peu à écrire. Mais c'est encore plus embarrassant pour find. Il perd même s'il n'y a rien à écrire du tout contre les fichiers 200K (13M de données de pipe) pour grep:

time find /usr -name lwevhewoivhol

find peut être aussi rapide que grep, cependant

Il s'avère que la stupidité de find avec name ne s'étend pas aux autres tests. Utilisez plutôt une expression régulière et le problème a disparu:

:> time find "$HOME"/ -regex '\.txt$' >/dev/null     

real    0m0.679s
user    0m0.264s
sys     0m0.410s

Je suppose que cela peut être considéré comme un bug. Quiconque souhaite déposer un rapport de bogue? Ma version est find (GNU findutils) 4.6.0

1
Hauke Laging

Remarque : Je suppose que vous voulez dire find . -name filename (sinon, vous cherchez des choses différentes; find filename examine en fait un chemin appelé nom_fichier, qui pourrait ne contenir presque aucun fichier, et donc sortir très rapidement).


Supposons que vous ayez un répertoire contenant cinq mille fichiers. Sur la plupart des systèmes de fichiers, ces fichiers sont en fait stockés dans une structure arbre , qui permet de localiser rapidement n'importe quel fichier donné.

Ainsi, lorsque vous demandez à find de localiser un fichier dont le nom ne nécessite qu'une vérification, find va demander pour ça fichier, et ce fichier uniquement, au système de fichiers sous-jacent, qui lira très peu de pages du stockage de masse. Donc, si le système de fichiers vaut son sel, cette opération s'exécutera beaucoup plus rapidement que parcourant tout l'arborescence pour récupérer toutes les entrées.

Lorsque vous demandez simplement find mais c'est exactement ce que vous faites, vous parcourez tout l'arbre, en lisant. Chaque. Célibataire. Entrée. Avec de gros répertoires, cela pourrait être un problème (c'est exactement la raison pour laquelle plusieurs logiciels, ayant besoin de stocker de nombreux fichiers sur le disque, créeront des "arborescences de répertoires" de deux ou trois composants en profondeur: de cette façon, chaque feuille ne doit contenir que moins des dossiers).

0
LSerni