Jai essayé les deux commandes et la commande find | grep "filename"
est plusieurs fois plus lente que la simple find "filename"
commande.
Quelle serait une explication correcte de ce comportement?
Commentaires
- Vous listent chaque fichier avec find, puis transmettent les données à grep pour quil les traite. Avec find utilisé dessus ‘, vous manquez létape de passer chaque fichier listé à grep pour analyser la sortie. Ce sera donc plus rapide.
- Plus lent dans quel sens? Les commandes prennent-elles un temps dexécution différent?
- Je ne peux ‘ reproduire cela localement. Si quoi que ce soit,
time find "$HOME" -name '.profile'
signale une durée plus longue quetime find "$HOME" | grep -F '.profile'
. (17 contre 12). - @JenniferAnderson Jai couru les deux à plusieurs reprises. Les 17 et 12 secondes sont des moyennes. Et oui, la variante
grep
correspondra nimporte où dans le résultatfind
, alors quelle correspondra avecfind -name
ne correspondrait que exactement (dans ce cas). - Oui,
find filename
serait rapide . Jai un peu supposé que cétait une faute de frappe et que lOP signifiaitfind -name filename
. Avecfind filename
, seulfilename
serait examiné (et rien dautre).
Réponse
(Je suppose que GNU find
ici)
En utilisant uniquement
find filename
serait rapide, car il renverrait simplement filename
, ou les noms à lintérieur de filename
sil sagit « dun répertoire, ou une erreur si ce nom nexistait pas dans le répertoire courant. Cest une opération très rapide, similaire à ls filename
(mais récursive si filename
est un répertoire).
Dans contraste,
find | grep filename
permettrait à find
de générer une liste de tous noms à partir de le répertoire courant et ci-dessous, que grep
filtrerait alors. 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 chercherait filename
comme nom dun fichier normal nimporte où dans le répertoire actuel ou ci-dessous.
Ce sera aussi rapide (ou comparativement rapide) que find | grep filename
, mais le grep
la solution ferait correspondre filename
au chemin complet de chaque nom trouvé, de la même manière que -path "*filename*"
ferait avec find
.
La confusion vient dun malentendu sur la façon dont find
fonctionne.
Lutilitaire prend un certain nombre de chemins et renvoie tous les noms sous ces chemins.
Vous pouvez alors restreindre les noms renvoyés à laide de différents tests pouvant agir sur le nom du fichier, le chemin, lhorodatage, la taille du fichier, le type de fichier, etc.
Quand vous dites
find a b c
vous demandez à find
de lister tous les noms disponibles sous les trois chemins a
, b
et c
. Sil sagit de noms de fichiers normaux dans le répertoire courant, ils seront renvoyés. Si lun dentre eux est le nom dun répertoire, il sera renvoyé avec tous les autres noms à lintérieur de ce répertoire.
Quand je le fais
find . -type f -name "filename"
Ceci génère une liste de tous les noms dans le répertoire courant (.
) et ci-dessous. Ensuite, il restreint les noms à ceux des fichiers normaux, cest-à-dire pas des répertoires, etc., avec -type f
. Ensuite, il y a une autre restriction aux noms qui correspondent à filename
en utilisant -name "filename"
. La chaîne filename
peut être un modèle de remplacement de nom de fichier, tel que *.txt
(noubliez 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 simplement tous les noms au chemin .profile
(il ny a quun seul nom, celui de ce fichier).
Ensuite, cd
monte dun niveau et réessaye:
$ cd .. $ pwd /home $ find .profile find: .profile: No such file or directory
Le ne peut désormais trouver aucun chemin appelé .profile
.
Cependant, si je l’obtiens pour regarder le répertoire courant, puis limite les noms renvoyés à seulement .profile
, il trouve à partir de là également:
$ pwd /home $ find . -name ".profile" ./kk/.profile
Commentaires
Réponse
Explication non technique: recherche de Jack dans une foule est plus rapide que de chercher tout le monde dans une foule et déliminer tout le monde sauf Jack.
Commentaires
- Le problème est que lOP sattend à ce que Jack être la seule personne dans la foule. Si cest le cas, ils ‘ ont de la chance.
find jack
listerajack
sil ‘ est un fichier appeléjack
, ou tous les noms du répertoire sil ‘ est un répertoire. ‘ est une mauvaise compréhension du fonctionnement defind
.
Réponse
Je nai pas encore compris le problème mais je peux fournir quelques informations supplémentaires.
Comme pour Kusalananda, lappel find | grep
est clairement plus rapide sur mon système ce qui na pas beaucoup de sens. Au début, jai supposé une sorte de problème de mise en mémoire tampon; que lécriture sur la console ralentit le temps jusquau prochain appel système pour lire le nom de fichier suivant. Lécriture sur un tube est très rapide: environ 40MiB / s même pour les écritures de 32 octets (sur mon système plutôt lent; 300 Mo / s pour une taille de bloc de 1MiB). Jai donc supposé que find
pouvait lire plus rapidement à partir du système de fichiers lors de lécriture dans un tube (ou fichier) afin que les deux opérations de lecture des chemins de fichiers et décriture sur la console puissent sexécuter en parallèle ( ce que find
en tant que processus de thread unique ne peut pas faire seul.
Cest find
« s fault
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 dincroyablement stupide (quoi que ce soit). Cest juste savère être assez incompétent pour exécuter -name "*.txt"
.
Cela pourrait dépendre du rapport entrée / sortie
Vous pourriez penser que find -name
gagne sil y a très peu à écrire. Mais cela devient plus embarrassant pour find
. Il perd même sil ny a rien à écrire du tout contre 200 000 fichiers (13 Mo de données de canal) pour grep
:
time find /usr -name lwevhewoivhol
find
peut être aussi rapide que grep
, bien que
Il savè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 est parti:
:> 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 bogue. Quelquun veut-il déposer un rapport de bogue? Ma version est find (GNU findutils) 4.6.0
Commentaires
- Dans quelle mesure vos horaires sont-ils reproductibles? Si vous avez effectué le test
-name
en premier, il se peut quil ait été plus lent car le contenu du répertoire nétait pas mis en cache. (Lors du test de-name
et-regex
, je trouve quils prennent à peu près le même temps, au moins une fois que leffet de cache a été pris en compte. Bien sûr, il peut simplement sagir dune version différente defind
…) - @psmears Bien sûr, jai fait ces tests plusieurs fois. Le problème de la mise en cache a été mentionné même dans les commentaires de la question avant la première réponse. Ma version
find
est find (GNU findutils) 4.6.0 - Pourquoi est-il surprenant que lajout de
-name '*.txt'
ralentissefind
? Il doit faire un travail supplémentaire, tester chaque nom de fichier. - @Barmar Dune part, ce travail supplémentaire peut être fait extrêmement rapidement. Dun autre côté, ce travail supplémentaire économise dautres travaux.
find
doit écrire moins de données. Et lécriture sur un tube est une opération beaucoup plus lente. - Lécriture sur un disque est très lente, lécriture sur un tube nest pas si mal, elle copie simplement dans un tampon du noyau. Notez que lors de votre premier test, écrire plus dans
/dev/null
a utilisé en quelque sorte moins de temps système.
Réponse
Remarque : Je suppose que vous voulez dire find . -name filename
(sinon, vous « cherchez des choses différentes; find filename
recherche en fait un chemin appelé filename , qui peut ne contenir presque aucun fichier, doù une sortie très rapide).
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 arborescente , qui permet de localiser rapidement un fichier donné.
Ainsi, lorsque vous demandez à find
de localiser un fichier dont le nom ne nécessite quune vérification, find
vous le demandera pour ce fichier, et ce fichier uniquement, vers le système de fichiers sous-jacent, qui lira très peu de pages du stockage de masse. Donc, si le système de fichiers en vaut la peine, cette opération s’exécutera beaucoup plus rapidement que traversant l’arborescence entière pour récupérer toutes les entrées.
Lorsque vous demandez un find
, mais cest exactement ce que vous faites, vous parcourez tout larbre, en lisant. Chaque. Unique. Entrée. Avec de grands répertoires, cela peut être un problème (cest exactement la raison pour laquelle plusieurs logiciels, ayant besoin de stocker beaucoup de fichiers sur le disque, créeront des « arborescences de répertoires » à deux ou trois composants: de cette façon, chaque feuille na besoin que de contenir moins de fichiers) .
Réponse
Supposons que le fichier / john / paul / george / ringo / beatles existe et le fichier que vous recherchez sappelle « stones »
find / stones
find comparera « beatles » à « stones » et le lâchera quand le « s » et « b » ne correspondent pas .
find / | grep stones
Dans ce cas, find passera « / john / paul / george / ringo / beatles » à grep et grep wil Je dois parcourir tout le chemin avant de déterminer si cest une correspondance.
grep fait donc beaucoup plus de travail, cest pourquoi cela prend plus de temps
Commentaires
- Avez-vous essayé?
- Le coût des comparaisons de chaînes (extrêmement simples et bon marché) est complètement éclipsé par le coût des E / S (ou simplement des appels système si mis en cache) des recherches de répertoire.
- grep isn ‘ une comparaison de chaînes, sa comparaison dexpressions régulières qui signifie quil doit parcourir toute la chaîne jusquà ce quil trouve un match ou atteint la fin. Les recherches dans les répertoires sont les mêmes quoi quil arrive.
- @Paranoid Hm, de quelle version de find parlez-vous? Cela ‘ ne ressemble en rien à la find I ‘ m utilisée dans debian.
find filename
renverrait uniquementfilename
sifilename
nétait pas de type répertoire (ou était de type répertoire, mais navait aucune entrée elle-même)