Для чого вам потрібен ./ (крапка-коса риса) перед виконуваним файлом або ім'ям сценарію, щоб запустити його в 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
Це найкращий документ з цього питання, який я до цього часу натрапив
одігіт

Відповіді:


307

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

Коли ви вводите команду, оболонка шукає список каталогів, визначений PATHзмінною. Поточний каталог відсутній у цьому списку.

Причиною відсутності поточного каталогу у цьому списку є безпека.

Скажімо, ви root і перейдіть до каталогу іншого користувача та введіть slзамість ls. Якщо поточний каталог знаходиться PATH, оболонка спробує виконати slпрограму в цьому каталозі (оскільки іншої slпрограми немає ). Ця slпрограма може бути шкідливою.

Він працює з ./тим, що POSIX вказує, що ім'я команди, яке містить а, /буде використовуватися безпосередньо як ім'я файлу, пригнічуючи пошук у $PATH. Ви могли використовувати повний шлях для точно такого ж ефекту, але ./він коротший і простіший в написанні.

EDIT

Ця slчастина була лише прикладом. Каталоги в PATHпошуку здійснюються послідовно, і коли проводиться збіг, виконується програма. Отже, залежно від того, як PATHвиглядає, введення звичайної команди може бути, а може бути недостатньо для запуску програми в поточному каталозі.


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

13
Просто примітка для всіх, хто говорить, що це лише в Unix, а не в Windows, це те саме в Powershell - .\my.batдля виконання потрібно виконати і т.д.
manojlds

1
@gaearon ergh, я сказав "не псевдонім", коли це повинно було бути "суворо псевдонімом".
Чарльз Даффі

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. Якщо це не так (як це стосується Manag.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

шукав би:

  • по відношенню до ХСЗ спочатку
  • відносно PATH після

Тоді, якщо ви хотіли бігти /bin/someprogзі свого дистрибутива, ви зробили:

someprog

Іноді це може спрацювати, але інші не зможуть, тому що ви можете опинитися в каталозі, який містить іншу незв'язану someprogпрограму.

Таким чином, ви незабаром дізнаєтесь, що це не є надійним, і ви в кінцевому підсумку завжди використовуєте абсолютні шляхи, коли хочете використовувати PATH, тому перемагаючи мету PATH.

Це також, чому наявність відносних шляхів у вашій PATH - це дійсно погана ідея. Я дивлюся на тебеnode_modules/bin ,.

І навпаки, припустимо, що працює:

./someprog

Шукав би:

  • відносно перших
  • відносно ХСН після

Тоді, якби ви просто завантажили скрипт 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
... FYI, в #bash на irc.freenode.org ми постійно виправляємо непорозуміння, про які люди дізналися з TLDP (зокрема, Посібник з розширеного керування). Як таке, спрямовувати людей там ... можливо, не ідеально. (Нашою бажаною вступною документацією є mywiki.wooledge.org/BashGuide )
Чарльз Даффі

-2

Усі мають чудову відповідь на питання, і так, це застосовується лише при запуску його в поточному каталозі, якщо тільки ви не включите абсолютний шлях. Дивіться мої зразки нижче.

Крім того, (крапка-штрих) мала сенс для мене, коли я маю команду в дочірній папці 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.