Sous Linux,
cd /tmp
mkdir foo; cd foo
Maintenant, en cours d'exécution
find . -name 'foo'
ne donne aucune sortie. Alors que courir
find /tmp/foo -name 'foo'
Donne la sortie /tmp/foo
qui n'a pas de sens pour moi. Quelqu'un peut-il expliquer pourquoi?
./
cela ne correspond pasfoo
find
.bar
qui pointe vers un fichierfoo
qui est en dehors du chemin de recherche. Cela correspond-il ou non?.
et/tmp/foo
ne sont pas les mêmes - ce sont deux liens durs différents vers le même répertoire;find /tmp/foo/. -name 'foo'
ne trouve rien non plus.find /tmp/foo -name 'foo'
, je demandais à bash de trouver dans le répertoire/tmp/foo
, un fichier dont le nom est "foo". Parce que le répertoire/tmp/foo
est vide, il ne devrait rien avoir retourné. Je ne comprends pas pourquoi il revient/tmp/foo
. D'un autre côté, quand je coursfind . -name 'foo'
, je demandais à bash la même chose, c'est-à-dire trouver un fichier dans le répertoire courant (qui se trouvait être/tmp/foo
), dont le nom est 'foo', et cela ne renvoie rien de sensé.Réponses:
find
traverse la ou les arborescences de répertoires spécifiées et évalue l'expression donnée pour chaque fichier qu'il trouve. La traversée commence au chemin donné. Voici un résumé dufind . -name foo
fonctionnement:.
.
) correspond-il au modèlefoo
? Non, alors ne fais rien.Il se trouve que
/tmp/foo
c'est un autre nom pour le même répertoire. Maisfind
ne sait pas cela (et il n'est pas censé essayer de le découvrir)..
, et pour chaque entrée, effectuer le processus de traversée..
and..
, quifind
ne traverse pas récursivement. Le travail est donc terminé.Et
find /tmp/foo
:/tmp/foo
foo
) correspond-il au modèlefoo
? Oui, donc la condition correspond./tmp/foo
, et pour chaque entrée, effectuer le processus de traversée..
and..
, quifind
ne traverse pas récursivement. Le travail est donc terminé.Il se trouve que
.
et/tmp/foo
sont le même répertoire, mais cela ne suffit pas à garantir quefind
a le même comportement sur les deux. Lafind
commande permet de distinguer les chemins d'accès au même fichier; le-name
prédicat en fait partie.find /tmp/foo -name foo
correspond au répertoire de départ ainsi qu'à tout fichier en dessous appeléfoo
.find . -name .
ne correspond qu'au répertoire de départ (.
ne peut jamais être trouvé lors d'une traversée récursive).la source
.
et..
. (Sifind
parcouru.
récursivement, il finirait par parcourir le répertoire encore et encore et encore et…).
et..
ne sont pas seulement des notations spéciales, ils apparaissent comme des entrées de répertoire.Il n'y a pas de normalisation des arguments de ligne de commande avant l'application des tests. Ainsi, les résultats diffèrent selon le chemin utilisé (si des liens symboliques sont impliqués):
Dans «votre cas», les deux appels donneraient le même résultat, ce qui pourrait être (plus) déroutant. Vous pouvez utiliser
-mindepth 1
si vous voulez que les points de départ soient ignorés (peut être non POSIX).la source
-mindepth 1
travaux. Cependant, je ne comprends toujours pas pourquoifind . -name 'foo'
et je mefind /tmp/foo -name 'foo'
comporte différemment.(gnu) find affiche toutes les correspondances trouvées dans le chemin fourni à la commande car il commence sa comparaison avec les arguments de la ligne de commande, descendant plus profondément dans la structure de répertoires à partir de là (donc,
-maxdepth 0
limite les tests au niveau de base ou aux arguments de la ligne de commande uniquement, tandis que-mindepth 1
ignore les arguments de la ligne de commande commeman find
expliqué). C'est la raison pour laquellefind /tmp/foo -name 'foo'
donnera une correspondance même si le répertoire lui-même est vide.find . -name 'foo'
d'autre part, ne donnera aucun résultat car.
(point) est un fichier spécial qui agit comme un lien dur vers le même inode que/tmp/foo
- c'est comme un nom de fichier séparé (bien que spécial) et non pas un lien symbolique ou une expression qui est soumis à expansion du chemin par le shell. Par conséquent, le premier test appliqué par find aux arguments de ligne de commande dans l'exemple donné n'affichera aucune correspondance, car en.
effet ne correspond pas au modèle de nom défini dans-name 'foo'
. Pas/tmp/foo/.
plus qu'un test de-name
modèle n'est effectué sur le nom de base du chemin uniquement (voirman find
), ce qui est encore le cas.
.Bien que ce comportement ne puisse pas être attendu ou semble intuitif du point de vue de l'utilisateur (et oui, cela m'a également dérouté au début), il ne constitue pas un bogue mais correspond à la logique et aux fonctionnalités décrites dans les pages man et info de ( gnu) trouver.
la source
J'ai essayé de commenter la réponse de Gilles, mais c'était trop long pour tenir dans un commentaire. Pour cette raison, je le mets en réponse à ma propre question.
L'explication de Gilles (et celle de Shevek également) est claire et logique. Le point clé ici est que non seulement
find
essaie de faire correspondre les noms de fichier pour les fichiers à l'intérieur des chemins donnés (récursivement), mais aussi, il essaie de faire correspondre le nom de base des chemins donnés eux-mêmes.D'un autre côté, existe-t-il une preuve que c'est ainsi que l'
find
on suppose que cela fonctionne, plutôt que d'être un bug? À mon avis, il serait préférable de ne pas rendre les résultats incohérents pourfind .
etfind ABSOLUTE-PATH
parce que l'incohérence est toujours déroutante et pourrait perdre beaucoup de temps au développeur à essayer de comprendre "ce qui n'allait pas". Dans mon cas, j'écrivais un script et le chemin était emprunté à une variable. Donc, pour que mon script fonctionne correctement, je peux penser à écrirefind $path/. -name 'pattern'
.Enfin, je pense qu'il est possible d'obtenir des résultats cohérents
find
en remplaçant toujours le.
par le répertoire actuel avant de continuer.la source
Aucun objet n'est nommé
foo
dans le répertoire où vous avez commencé la recherche relative.Vous avez raison de supposer que
gfind
c'est bogué lorsqu'il signale l'/tmp/foo
utilisation du nom absolu comme répertoire de démarrage.Gfind
a divers écarts par rapport à la norme, il semble que vous en ayez trouvé un autre. Lorsque vous aimez une solution plus conforme, je recommandesfind
que cela fasse partie duschilytools
.-name
s'applique aux résultats de la recherche dans l'annuaire. Aucun des deux cas que vous mentionnez ne renverra une entréefoo
de répertoire d'unereaddir()
opération.la source
find --version
: find (GNU findutils) 4.4.2 Copyright (C) 2007 Free Software Foundation, Inc. Licence GPLv3 +: GNU GPL version 3 ou ultérieure < gnu.org/licenses/gpl.html >find
(certifié POSIX),gfind
etsfind
; le problème existe uniquement lorsque vous utilisezgfind
. Sous Linux,gfind
n'est pas installé sous son nom natif mais sous le nomfind
.find /tmp/foo -name foo
de sortir/tmp/foo
. (Cc @York) Il s'agit du comportement d'OpenBSDfind
, de GNUfind
, de BusyBoxfind
, de Solarisfind
et de tout autre compatible POSIXfind
(«Le principal doit être évalué comme vrai si le nom de base du nom de fichier examiné correspond au modèle (…)» - lorsque le nom de fichier est celui qui est passé comme opérande de chemin, aucunreaddir
appel n'est impliqué).