Pourquoi avez-vous besoin de ./ (barre oblique) avant le nom de l'exécutable ou du script pour l'exécuter dans bash?

288

Lors de l'exécution de scripts en bash, je dois écrire ./au début:

$ ./manage.py syncdb

Si je ne le fais pas, j'obtiens un message d'erreur:

$ manage.py syncdb
-bash: manage.py: command not found

Quelle est la raison pour ça? Je pensais que c'était .un alias pour le dossier actuel, et donc ces deux appels devraient être équivalents.

Je ne comprends pas non plus pourquoi je n'ai pas besoin ./lors de l'exécution d'applications, telles que:

user:/home/user$ cd /usr/bin
user:/usr/bin$ git

(qui fonctionne sans ./)

Dan Abramov
la source
4
Voici le meilleur document sur le sujet que j'ai rencontré jusqu'à présent: linfo.org/dot_slash.html
odigity

Réponses:

307

Parce que sous Unix, généralement, le répertoire actuel n'est pas dans $PATH.

Lorsque vous tapez une commande, le shell recherche une liste de répertoires, comme spécifié par la PATHvariable. Le répertoire actuel ne figure pas dans cette liste.

La raison de ne pas avoir le répertoire actuel sur cette liste est la sécurité.

Disons que vous êtes root et allez dans le répertoire d'un autre utilisateur et tapez slau lieu de ls. Si le répertoire courant se trouve PATH, le shell essaiera d'exécuter le slprogramme dans ce répertoire (puisqu'il n'y a pas d'autre slprogramme). Ce slprogramme pourrait être malveillant.

Il fonctionne avec ./car POSIX spécifie qu'un nom de commande qui contient un /sera utilisé directement comme nom de fichier, supprimant une recherche dans $PATH. Vous auriez pu utiliser le chemin complet pour obtenir exactement le même effet, mais il ./est plus court et plus facile à écrire.

ÉDITER

Cette slpartie n'était qu'un exemple. Les répertoires PATHsont recherchés séquentiellement et lorsqu'une correspondance est établie, le programme est exécuté. Ainsi, selon l' PATHapparence, taper une commande normale peut ou peut ne pas être suffisant pour exécuter le programme dans le répertoire en cours.

cnicutar
la source
47
Vous n'avez pas besoin de taper quoi que ce soit. L'utilisateur peut simplement avoir téléchargé un package malveillant contenant un lsexécutable.
Juliano
13
Juste une note pour tout le monde qui dit que ce n'est que sous Unix et non sous Windows, c'est la même chose dans Powershell - vous devez faire .\my.batetc pour exécuter
manojlds
1
@gaearon ergh, j'ai dit "n'est pas un alias", alors que cela aurait dû être "est strictement un alias".
Charles Duffy
4
C'était une explication très utile. Il y a plus de 20 ans, lorsque je travaillais un peu avec DOS, je pense que CMD vérifierait le répertoire actuel, puis ALORS le CHEMIN, donc le comportement de Linux n'était pas ce à quoi je m'attendais, mais cela fait beaucoup de sens.
TecBrat
2
@cnicutar: Fait intéressant aujourd'hui, j'ai trouvé qu'il existe une slcommande appelée locomotive à vapeur bien qu'elle ne soit pas disponible par défaut ;-)
blackSmith
51

Lorsque bash interprète la ligne de commande, il recherche les commandes aux emplacements décrits dans la variable d'environnement $PATH. Pour le voir, tapez:

echo $PATH

Vous aurez quelques chemins séparés par des deux-points. Comme vous le verrez, le chemin actuel .n'est généralement pas dans $PATH. Bash ne peut donc pas trouver votre commande si elle se trouve dans le répertoire courant. Vous pouvez le changer en ayant:

PATH=$PATH:.

Cette ligne ajoute le répertoire courant $PATHafin que vous puissiez faire:

manage.py syncdb

Il n'est pas recommandé car il a un problème de sécurité, et vous pouvez avoir des comportements étranges, car cela .varie selon le répertoire dans lequel vous vous trouvez :)

Éviter:

PATH=.:$PATH

Comme vous pouvez «masquer» une commande standard et ouvrir la porte à une brèche de sécurité :)

Juste mes deux cents.

neuro
la source
42

Votre script, dans votre répertoire personnel, ne sera pas trouvé lorsque le shell $PATH variable d'environnement pour trouver votre script.

Le ./dit 'regardez dans le répertoire courant pour mon script plutôt que de regarder tous les répertoires spécifiés dans $PATH'.

mdm
la source
5

Lorsque vous incluez le '.' vous donnez essentiellement le "chemin complet" au script bash exécutable, donc votre shell n'a pas besoin de vérifier votre variable PATH. Sans le '.' votre shell va regarder dans votre variable PATH (que vous pouvez voir en exécutant echo $PATHpour voir si la commande que vous avez tapée se trouve dans l'un des dossiers de votre PATH. Si ce n'est pas le cas (comme c'est le cas avec manage.py), il le dit Impossible de trouver le fichier. Il est considéré comme une mauvaise pratique d'inclure le répertoire actuel dans votre PATH, ce qui est expliqué assez bien ici: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html

Mark Drago
la source
2

Sur * nix, contrairement à Windows, le répertoire courant n'est généralement pas dans votre $PATHvariable. Ainsi, le répertoire actuel n'est pas recherché lors de l'exécution des commandes. Vous n'avez pas besoin ./d'exécuter des applications car ces applications sont dans votre $ PATH; ils sont très probablement dans /binou /usr/bin.

Anomie
la source
1

Cette question a déjà des réponses impressionnantes, mais je voulais ajouter que, si votre exécutable est sur le PATH, et que vous obtenez des sorties très différentes lorsque vous exécutez

./executable

à ceux que vous obtenez si vous courez

executable

(disons que vous rencontrez des messages d'erreur avec l'un et non avec l'autre), le problème pourrait être que vous avez deux versions différentes de l'exécutable sur votre machine: une sur le chemin et l'autre non.

Vérifiez cela en exécutant

quel exécutable

et

whereis executable

Il a résolu mes problèmes ... J'avais trois versions de l'exécutable, dont une seule a été compilée correctement pour l'environnement.

KR_Henninger
la source
0

Justification de la /règle POSIX PATH

La règle a été mentionnée à: Pourquoi avez-vous besoin de ./ (barre oblique) avant le nom de l'exécutable ou du script pour l'exécuter dans bash?mais je voudrais expliquer pourquoi je pense que c'est une bonne conception plus en détail.

Premièrement, une version complète explicite de la règle est:

  • si le chemin contient /(par exemple ./someprog, /bin/someprog,./bin/someprog ): CWD est utilisé et est non PATH
  • si le chemin ne contient pas /(par exemple someprog): PATH est utilisé et CWD ne l'est pas

Supposons maintenant que l'exécution:

someprog

rechercherait:

  • par rapport à CWD en premier
  • par rapport à PATH après

Ensuite, si vous vouliez courir à /bin/someprogpartir de votre distribution, et vous avez fait:

someprog

cela fonctionnerait parfois, mais d'autres échoueraient, car vous pourriez être dans un répertoire qui contient un autre sans rapport someprog programme .

Par conséquent, vous apprendrez bientôt que ce n'est pas fiable et vous finirez toujours par utiliser des chemins absolus lorsque vous souhaitez utiliser PATH, ce qui ira à l'encontre de l'objectif de PATH.

C'est aussi pourquoi avoir des chemins relatifs dans votre PATH est une très mauvaise idée. Je te regarde,node_modules/bin .

À l'inverse, supposons que l'exécution:

./someprog

Rechercherait:

  • par rapport à PATH en premier
  • par rapport à CWD après

Ensuite, si vous venez de télécharger un script à someprogpartir d'un référentiel git et que vous vouliez l'exécuter à partir de CWD, vous ne seriez jamais sûr que c'est le programme réel qui s'exécuterait, car peut-être que votre distribution a un:

/bin/someprog

qui est dans votre CHEMIN à partir d'un paquet que vous avez installé après avoir trop bu après Noël l'année dernière.

Par conséquent, encore une fois, vous seriez obligé de toujours exécuter des scripts locaux relatifs à CWD avec des chemins d'accès complets pour savoir ce que vous exécutez:

"$(pwd)/someprog"

ce qui serait également extrêmement ennuyeux.

Une autre règle que vous pourriez être tenté de proposer serait:

les chemins relatifs utilisent uniquement PATH, les chemins absolus uniquement CWD

mais encore une fois, cela oblige les utilisateurs à toujours utiliser des chemins absolus pour les scripts non-PATH avec "$(pwd)/someprog" .

La /règle de recherche de chemin offre une solution simple à retenir au problème de:

  • barre oblique: ne pas utiliser PATH
  • pas de barre oblique: utilisez uniquement PATH

ce qui rend super facile de toujours savoir ce que vous exécutez, en s'appuyant sur le fait que les fichiers dans le répertoire en cours peuvent être exprimés soit comme ./somefileou somefile, et donc il donne une signification particulière à l'un d'eux.

Parfois, c'est légèrement ennuyeux que vous ne puissiez pas rechercher par some/prograpport à PATH, mais je ne vois pas de solution plus saine à cela.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
-1

Lorsque le script n'est pas dans le chemin, il est nécessaire de le faire. Pour plus d'informations, consultez http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html

Gayan Hewa
la source
5
... Pour info, dans #bash sur irc.freenode.org, nous corrigeons constamment les malentendus que les gens ont appris de TLDP (en particulier le Guide avancé de Bash). En tant que tel, diriger les gens là-bas n'est ... peut-être pas idéal. (Notre documentation d'introduction préférée est mywiki.wooledge.org/BashGuide )
Charles Duffy
-2

Tous ont une excellente réponse à la question, et oui, cela ne s'applique que lors de son exécution sur le répertoire en cours, sauf si vous incluez le chemin absolu. Voir mes exemples ci-dessous.

En outre, le (point-slash) était logique pour moi lorsque j'ai la commande sur le dossier enfant tmp2 (/ tmp / tmp2) et qu'il utilise (double point-slash).

ÉCHANTILLON:

[fifiip-172-31-17-12 tmp]$ ./StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ /tmp/StackO.sh

Hello Stack Overflow

[fifi@ip-172-31-17-12 tmp]$ mkdir tmp2

[fifi@ip-172-31-17-12 tmp]$ cd tmp2/

[fifi@ip-172-31-17-12 tmp2]$ ../StackO.sh

Hello Stack Overflow
FIFI
la source