Pourquoi est-ce que find imprime un «./» de tête si aucun chemin n'est indiqué?

13

Pourquoi est-ce qui findimprime un conduit ./à des résultats si aucun chemin n'est indiqué?

$ find
./file1
./file2
./file3

Quelle est la raison de ne pas l'imprimer?

$ find
file1
file2
file3
nr
la source

Réponses:

16

La raison pour laquelle vous voyez cela est que le développeur de GNU a choisi de fournir un comportement "raisonnable" quand aucun chemin n'est indiqué. En revanche, POSIX n'indique pas que le paramètre est facultatif:find find

L' findutilitaire doit récursivement descendre la hiérarchie de répertoires de chaque fichier spécifié par chemin , en évaluant une expression booléenne composée des primaires décrites dans la section OPERANDS pour chaque fichier rencontré. Chaque opérande de chemin doit être évalué tel qu'il a été fourni, y compris tous les <slash>caractères de fin ; tous les chemins d'accès pour les autres fichiers rencontrés dans la hiérarchie doivent consister en la concaténation de l'opérande de chemin d'accès actuel, a <slash>si l'opérande de chemin d'accès actuel ne s'est pas terminé par un, et le nom de fichier relatif à l'opérande de chemin d'accès. La partie relative ne doit contenir aucun composant point ou point-point, pas de finet uniquement des <slash>caractères uniques entre les composants de chemin d'accès.

Vous pouvez voir la différence dans le synopsis pour chacun. GNU a (comme c'est la convention) des éléments optionnels entre crochets:

find [-H] [-L] [-P] [-D debugopts] [-Olevel] [starting-point...]
       [expression]

alors que POSIX n'indique pas qu'il peut être facultatif:

find [-H|-L] path... [operand_expression...]

Dans le programme GNU, cela se fait en ftsfind.c:

  si (vide)
    {
      / *
       * Nous utilisons ici une variable temporaire car certaines actions modifient
       * le chemin temporairement. Par conséquent, si nous utilisons une constante de chaîne,
       * nous obtenons un coredump. Le meilleur exemple de cela est si nous disons
       * "find -printf% H" (notez, pas "find. -printf% H").
       * /
      char defaultpath [2] = ".";
      return find (defaultpath);
    }

et un littéral "."est utilisé pour plus de simplicité. Vous verrez donc le même résultat avec

find

et

find .

car (et POSIX est d'accord) le chemin donné sera utilisé pour préfixer les résultats (voir ci-dessus pour la concaténation ).

Avec un peu de travail, on pouvait déterminer quand la fonctionnalité a été ajoutée pour la première fois; il était présent lors de la création initiale de "findutils" en 1996 (voir find.c):

+  /* If no paths are given, default to ".".  */
+  for (i = 1; i < argc && strchr ("-!(),", argv[i][0]) == NULL; i++)
+    process_top_path (argv[i]);
+  if (i == 1)
+    process_top_path (".");
+
+  exit (exit_status);
+}

Dans le journal des modifications de la découverte 3.8, cela était apparemment

Sat Dec 15 19:01:12 1990  David J. MacKenzie  (djm at egypt)

        * find.c (main), util.c (usage): Make directory args optional,
        defaulting to "."
Thomas Dickey
la source
11

Habituellement, on fait un post-traitement des fichiers et, dans ce cas, il peut y avoir un énorme avantage à démarrer le nom de fichier avec ./. En particulier, si un nom de fichier commence par -, une commande ultérieure pourrait interpréter ce nom de fichier comme une option. ./évite cela.

Par exemple, considérons un répertoire avec ces fichiers:

$ ls
--link  --no-clobber

Maintenant, imaginez comment cette commande fonctionnerait si les noms de fichiers étaient fournis sans le ./devant:

$ find -type f -exec cp -t ../ {} +

Nous pouvons illustrer le problème avec findlui-même. Exécutons-le dans le même répertoire que ci-dessus. Les oeuvres suivantes:

$ find ./*
./--link
./--no-clobber

Échoue:

$ find *
find: unknown predicate `--link'
Try 'find --help' for more information.
John1024
la source
1
Ca a du sens. Mais ensuite, il y a la question de savoir pourquoi il ne précède pas un "." quand tu cours find *.
nr
@nr Bon point. Je m'attends à ce qu'il se comporte de cette façon pour une sorte de compatibilité historique. J'ai ajouté à la réponse un exemple de la raison pour laquelle il s'agit d'un comportement indésirable.
John1024
3
Certaines versions de file demandent à l'utilisateur de donner un chemin (comme la découverte BSD sur OS X). Donc, vous devez généralement dire explicitement quelque chose comme find . -type f .... À partir de là, ce n'est pas un grand pas pour certaines versions de find (comme GNU find) de simplement par défaut .et de laisser tout le reste tel quel.
ilkkachu
1
La raison de find *ne pas afficher le .est parce que *répertorie tous les fichiers et dossiers, mais exclut .. Faites-le echo *dans un répertoire qui ne contient qu'un ou deux fichiers, et vous verrez qu'il .n'est pas répertorié. Ainsi, find *opère sur chaque fichier développé. C'est la même chose que si vous aviez dit find Desktop/depuis le répertoire personnel. Vous verrez la sortie commeDesktop/foo_bar.txt
Sergiy Kolodyazhnyy
1
@ John1024: Je pense que Mrigesh et Thomas Dickey ont correctement répondu à la question. Cette réponse indique pourquoi il est commode de findse comporter ainsi. Avez-vous des informations de référence faisant autorité pour étayer l'allégation implicite qui a findété conçue pour se comporter de cette manière pour cette raison?
G-Man dit `` Réintègre Monica ''
4

La findcommande a besoin de chemin (s) pour rechercher. Si nous n'en spécifions aucun, il utilise le répertoire courant ( .) comme point de départ. De même, si vous passez le chemin, par exemple /tmp, il considère cela comme son point de départ. Et donc les résultats.

Si répertoire courant:

        $ find
or
        $ find .

output:
        ./file1
        ./file2
        ./file3

Si /tmprépertoire:

        $ find /tmp

output:
        /tmp/file4
        /tmp/file5

Si abcrépertoire sous le répertoire courant:

        $ find abc

output:
        abc/file6
        abc/file7

Si plusieurs répertoires sous le répertoire actuel:

        $ find fu bar

output:
        fu/file10
        fu/file11
        bar/file8
        bar/file9
Mrigesh Priyadarshi
la source
Oui, je suis d'accord a findbesoin d'un chemin pour rechercher quoi que ce soit et qu'il par défaut dans le répertoire actuel. La question est de savoir pourquoi il imprime le ./début quand file.txtest le même que ./file.txt.
nr
1
ce n'est pas que trouver ajoute "." au début, il ajoute tout ce que vous lui donnez comme chemin, que ce soit "/ tmp" "abc" ou ".". Il renverra respectivement toutes les valeurs.
Mrigesh Priyadarshi
-2

Si vous ne spécifiez pas de chemin, la findcommande suppose ${PWD}que comme chemin et l'imprime sur sa sortie. L'utilisateur qui ne spécifie pas le chemin ne change pas le findfonctionnement. Et find fonctionne toujours avec les chemins par défaut.

MelBurslan
la source
1
Je vois. Mais si vous l'exécutez sous /tmp, ce $PWDn'est /tmppas le cas ./.
nr
si vous voulez voir le précédent /tmp, exécutez la commande find /tmpSi vous ne spécifiez pas de chemin, ce sera toujours le répertoire courant, qui est./
MelBurslan
1
Ce n'est pas que je veuille voir précéder /tmp. C'est que ça ne peut pas être $PWD.
nr
Mes excuses ${PWD}étaient le verbiage incorrect
MelBurslan
2
Non, il n'assume pas $ PWD. Comparez la sortie de find ., find $PWDet find(sans chemin, si votre recherche le prend en charge).
ilkkachu