Зачем вам нужно ./ (точка-косая черта) перед именем исполняемого файла или скрипта, чтобы запустить его в bash?


288

При запуске скриптов в bash, я должен написать ./в начале:

$ ./manage.py syncdb

Если я не, я получаю сообщение об ошибке:

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

Что является причиной этого? Я думал, .что это псевдоним для текущей папки, и поэтому эти два вызова должны быть эквивалентны.

Я также не понимаю, почему мне не нужно ./при запуске приложений, таких как:

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

(который работает без ./)


4
Это лучший документ по этому вопросу, с которым я когда-либо сталкивался: linfo.org/dot_slash.html
odigity

Ответы:


307

Потому что в Unix, как правило, текущий каталог не находится в $PATH.

При вводе команды оболочка просматривает список каталогов, как указано в PATHпеременной. Текущий каталог не в этом списке.

Причиной отсутствия текущего каталога в этом списке является безопасность.

Допустим, вы root и зайдите в каталог другого пользователя и наберите slвместо ls. Если текущий каталог находится PATH, оболочка попытается выполнить slпрограмму в этом каталоге (поскольку другой slпрограммы нет). Эта slпрограмма может быть вредоносной.

Это работает, ./потому что POSIX указывает, что имя команды, которое содержит a, /будет использоваться как имя файла напрямую, подавляя поиск в $PATH. Вы могли бы использовать полный путь для того же эффекта, но ./он короче и его легче написать.

РЕДАКТИРОВАТЬ

Эта slчасть была просто примером. Каталоги в PATHпоиске последовательно, и когда сопоставление установлено, эта программа выполняется. Таким образом, в зависимости от того PATH, как выглядит, ввода обычной команды может быть или не быть достаточно для запуска программы в текущем каталоге.


47
Вам не нужно ничего набирать. Пользователь, возможно, только что загрузил вредоносный пакет, содержащий lsисполняемый файл.
Джулиано

13
Просто всем, кто говорит, что это только в Unix, а не в Windows, то же самое в Powershell - вы должны выполнить и .\my.batт. Д., Чтобы выполнить
manojlds

1
@gaearon Эрг, я сказал "не псевдоним", когда это должно было быть "строго псевдоним".
Чарльз Даффи

4
Это было очень полезное объяснение. 20+ лет назад, когда я немного поработал с DOS, я думаю, что CMD проверит текущий каталог, а затем ПУТЬ, поэтому поведение Linux оказалось не таким, как я ожидал, но оно имеет ОЧЕНЬ смысл.
TecBrat

2
@cnicutar: Интересно, что сегодня я обнаружил, что есть slкоманда, называемая паровозом, хотя по умолчанию она недоступна ;-)
blackSmith

51

Когда bash интерпретирует командную строку, он ищет команды в местах, описанных в переменной среды $PATH. Чтобы увидеть это введите:

echo $PATH

У вас будет несколько путей, разделенных двоеточиями. Как вы увидите, текущий путь .обычно отсутствует $PATH. Поэтому Bash не может найти вашу команду, если она находится в текущем каталоге. Вы можете изменить это, имея:

PATH=$PATH:.

Эта строка добавляет текущий каталог, $PATHчтобы вы могли сделать:

manage.py syncdb

Это не рекомендуется, так как имеет проблему с безопасностью, плюс у вас может быть странное поведение, которое .зависит от каталога, в котором вы находитесь :)

Избегайте:

PATH=.:$PATH

Как вы можете «замаскировать» какую-то стандартную команду и открыть дверь для нарушения безопасности :)

Просто мои два цента.


42

Ваш скрипт, когда он находится в вашем домашнем каталоге, не будет найден, когда оболочка смотрит на $PATHпеременную окружения, чтобы найти ваш скрипт.

./Говорит «взгляд в текущей директории для моего сценария , а не смотря на все каталоги , указанные в $PATH».


5

Когда вы включаете «.» по сути, вы даете «полный путь» исполняемому скрипту bash, поэтому вашей оболочке не нужно проверять переменную PATH. Без '.' ваша оболочка будет искать переменную PATH (которую вы можете увидеть, выполнив echo $PATHкоманду, чтобы увидеть, находится ли введенная вами команда в какой-либо из папок в вашем PATH. Если это не так (как в случае с manage.py), она говорит это не удается найти файл. Включение текущего каталога в переменную PATH считается плохой практикой, что достаточно хорошо объяснено здесь: http://www.faqs.org/faqs/unix-faq/faq/part2/section-. 13.html


2

В * nix, в отличие от Windows, текущий каталог обычно не находится в вашей $PATHпеременной. Таким образом, текущий каталог не ищется при выполнении команд. Вам не нужно ./запускать приложения, потому что эти приложения находятся в вашем $ PATH; скорее всего они в /binили /usr/bin.


1

На этот вопрос уже есть несколько отличных ответов, но я хотел бы добавить, что, если ваш исполняемый файл находится в переменной PATH, и вы получаете очень разные результаты при запуске

./executable

к тем, которые вы получаете, если вы бежите

executable

(допустим, вы сталкиваетесь с сообщениями об ошибках с одним, а не с другим), тогда проблема может заключаться в том, что у вас есть две разные версии исполняемого файла на вашей машине: одна на пути, а другая нет.

Проверьте это, запустив

какой исполняемый файл

и

whereis executable

Это исправило мои проблемы ... У меня было три версии исполняемого файла, только одна из которых была правильно скомпилирована для среды.


0

Обоснование /правила POSIX PATH

Правило упоминалось здесь: зачем вам нужен ./ (точка-косая черта) перед именем исполняемого файла или скрипта, чтобы запустить его в bash? но я хотел бы объяснить, почему я думаю, что это хороший дизайн более подробно.

Во-первых, полная версия правила:

  • если путь содержит /(например ./someprog, /bin/someprog, ./bin/someprog): УХО используется и PATH не
  • если путь не содержит /(например someprog): PATH используется, а CWD - нет

Теперь предположим, что работает:

someprog

будет искать:

  • относительно CWD сначала
  • относительно PATH после

Затем, если вы хотите запустить /bin/someprogиз своего дистрибутива, и вы сделали:

someprog

иногда это будет работать, а в других - не получится, потому что вы можете находиться в каталоге, содержащем другую не связанную someprogпрограмму.

Таким образом, вы скоро узнаете, что это ненадежно, и в конечном итоге вы всегда будете использовать абсолютные пути, когда захотите использовать PATH, что приведет к поражению цели PATH.

Именно поэтому наличие относительных путей в вашем PATH - действительно плохая идея. Я смотрю на тебяnode_modules/bin .

И наоборот, предположим, что работает:

./someprog

Будет искать:

  • по отношению к PATH первым
  • относительно CWD после

Затем, если вы просто скачали скрипт someprogиз репозитория git и хотели запустить его из CWD, вы никогда не были бы уверены, что это именно та программа, которая будет запускаться, потому что, возможно, ваш дистрибутив имеет:

/bin/someprog

который находится в вашем ПУТИ из какого-то пакета, который вы установили после того, как выпили слишком много после Рождества в прошлом году.

Поэтому, опять же, вы будете вынуждены всегда запускать локальные сценарии относительно CWD с полными путями, чтобы знать, что вы запускаете:

"$(pwd)/someprog"

что было бы крайне раздражающим.

Другое правило, которое вы могли бы соблазнить, было бы:

относительные пути используют только PATH, абсолютные пути только CWD

но еще раз это заставляет пользователей всегда использовать абсолютные пути для сценариев, не относящихся к PATH "$(pwd)/someprog".

/Правило пути поиска предлагает простое вспомнить решение о проблеме:

  • косая черта: не использовать PATH
  • без косой черты: только использовать PATH

что позволяет очень легко всегда знать, что вы выполняете, полагаясь на то, что файлы в текущем каталоге могут быть выражены как ./somefileили somefile, и поэтому придает особое значение одному из них.

Иногда немного раздражает, что вы не можете искать по some/progотношению к PATH, но я не вижу более разумного решения этого.


-1

Когда сценарий не находится в пути, это необходимо сделать. Для получения дополнительной информации читайте http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html.


5
... К вашему сведению, в #bash на irc.freenode.org мы постоянно исправляем недоразумения, извлеченные людьми из TLDP (в частности, Advanced Bash Guide). Таким образом, направление туда людей ... может быть, не идеальное. (Наша предпочтительная вводная документация - mywiki.wooledge.org/BashGuide )
Чарльз Даффи,

-2

У All есть отличный ответ на вопрос, и да, это применимо только при запуске его в текущем каталоге, если только вы не указали абсолютный путь. Смотрите мои образцы ниже.

Кроме того, (точка-косая черта) имела смысл для меня, когда у меня есть команда для дочерней папки tmp2 (/ tmp / tmp2) и она использует (двойная точка-косая черта).

ОБРАЗЕЦ:

[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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.