Pourquoi find trouve-t-il parfois son argument de command line?

Sur Linux,

cd /tmp mkdir foo; cd foo 

Maintenant, courir

 find . -name 'foo' 

ne donne pas de 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?

find parcourt l'arborescence de directorys spécifié et évalue l'expression donnée pour chaque file qu'il trouve. La traversée commence au path donné. Voici un résumé de la façon de find . -name foo find . -name foo fonctionne:

  • Premier path sur la command line:.
    • Le nom de base ( . ) Correspond-il au motif foo ? Non, alors ne faites rien.
      Il se trouve que /tmp/foo est un autre nom pour le même directory. Mais find ne le sait pas (et ce n'est pas supposé essayer de le savoir).
    • Le path est-il un directory? Oui, alors parcourez-le. Énumérer les inputs dans . , et pour chaque input, effectuer le process de traversée.
      • Le directory est vide: il ne contient aucune input autre que . et .. , qui find ne traverse pas récursivement. Donc, le travail est terminé.

Et find /tmp/foo :

  • Premier path sur la command line: /tmp/foo
    • Le nom de base ( foo ) correspond-il au motif foo ? Oui, donc la condition correspond.
      • Il n'y a aucune action associée à cette condition, alors exécutez l'action par défaut, qui consiste à imprimer le path.
    • Le path est-il un directory? Oui, alors parcourez-le. Énumérer les inputs dans /tmp/foo , et pour chaque input, effectuer le process de traversée.
      • Le directory est vide: il ne contient aucune input autre que . et .. , qui find ne traverse pas récursivement. Donc, le travail est terminé.

Il se trouve que cela . et /tmp/foo sont le même directory, mais cela ne suffit pas pour garantir que find ait le même comportement sur les deux. La command find permet de distinguer les paths d'access au même file; le prédicat -name est l'un d'entre eux. find /tmp/foo -name foo correspond au directory de départ ainsi qu'à tout file sous- foo appelé foo . find . -name . correspond uniquement au directory de démarrage (.peu ne peut être trouvé lors d'une traversée récursive).

Il n'y a pas de normalisation des arguments de command line avant l'application des tests. Ainsi, les résultats diffèrent selon le path utilisé (si des liens symboliques sont impliqués):

 cd /tmp mkdir foo ln -s foo bar find /tmp/foo -name foo find /tmp/bar -name foo 

Dans votre cas, les deux appels donneraient le même résultat qui pourrait être (plus) déroutant. Vous pouvez utiliser -mindepth 1 si vous souhaitez ignorer les points de départ (peut être non-POSIX).

(gnu) find montre toutes les correspondances trouvées dans le path fourni à la command car il commence sa comparaison avec les arguments de la command line, descendant plus profondément dans la structure de directory à partir de là ( -maxdepth 0 confine les tests au niveau de base ou aux arguments de la command line seulement, alors que -mindepth 1 ignore les arguments de la command line comme l'explique l' man find ). C'est la raison pour laquelle find /tmp/foo -name 'foo' donnera une correspondance même si le directory lui-même est vide.

find . -name 'foo' find . -name 'foo' d'autre part ne donnera aucun résultat parce que . (dot) est un file spécial qui agit comme un lien vers le même inode que le file /tmp/foo . Il s'agit d'un nom de file séparé et non d'un lien symbolique ou d'une expression soumise à l'expansion du nom de domaine par le shell. Par conséquent, le premier test appliqué par find aux arguments de la command line dans l'exemple donné ne montre aucune correspondance, puisque . ne correspond en effet pas au model de nom défini dans -name 'foo' . Ni /tmp/foo/. car un test pour un model -name est effectué sur le nom de base du path uniquement (voir man find ), qui est là encore . .

Bien que ce comportement ne soit pas attendu ou n'apparaisse pas intuitif du sharepoint vue de l'user, il ne constitue pas un bug, mais correspond à la logique et à la fonctionnalité décrites dans les pages man et info de ( gnu) find.

J'ai essayé de commenter la réponse de Gilles, mais c'était trop long pour faire l'object d'un commentaire. Pour cette raison, je le mets en réponse à ma propre question.

L'explication de Gilles (et celle de Shevek aussi) est claire et logique. Le point key ici est que non seulement cherche à faire correspondre les noms de files pour les files à l'intérieur des paths donnés (récursivement), mais aussi, il essaie de faire correspondre le nom de base des paths donnés eux-mêmes.

D'autre part, y a-t-il une preuve que c'est la façon dont la find est supposée fonctionner, plutôt que d'être un bug? À mon avis, ce serait mieux si cela ne rend pas les résultats incohérents pour la find . et find ABSOLUTE-PATH parce que l'incohérence est toujours source de confusion et pourrait gaspiller beaucoup de time au développeur à essayer de comprendre «ce qui n'allait pas». Dans mon cas, j'écrivais un script, et le path était pris d'une variable. Donc, pour que mon script fonctionne correctement, je peux écrire find $path/. -name 'pattern' find $path/. -name 'pattern' .

Finalement, je pense que l'obtention de résultats cohérents pour find peut être obtenue en substituant toujours le . avec le directory courant avant de continuer.

Il n'y a pas d'object nommé foo dans le directory où vous avez démarré la search relative.

Vous avez raison en supposant que gfind est gfind quand il signale /tmp/foo en utilisant le nom absolu comme directory de départ.

Gfind a divers écarts par rapport à la norme, il semble que vous en avez trouvé un autre. Lorsque vous aimez une solution plus standard, je recommand sfind qui fait partie des schilytools .

-name s'applique aux résultats de search d'annuaire. Aucun des deux cas mentionnés ne renvoie une input de directory foo partir d'une opération readdir() .