Dlaczego potrzebujesz ./ (kropka-ukośnik) przed nazwą pliku wykonywalnego lub skryptu, aby uruchomić go w bash?

288

Kiedy uruchamiam skrypty w bash, muszę napisać ./na początku:

$ ./manage.py syncdb

Jeśli nie, otrzymuję komunikat o błędzie:

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

Jaki jest tego powód? Myślałem, że .to alias dla bieżącego folderu, dlatego te dwa połączenia powinny być równoważne.

Nie rozumiem też, dlaczego nie potrzebuję, ./gdy uruchamiam aplikacje, takie jak:

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

(który działa bez ./)

Dan Abramov
źródło
4
To najlepszy dokument w tej sprawie, z jakim się zetknąłem
odigity

Odpowiedzi:

307

Ponieważ w systemie Unix zwykle nie ma bieżącego katalogu $PATH.

Po wpisaniu polecenia powłoka wyszukuje listę katalogów określoną przez PATHzmienną. Bieżącego katalogu nie ma na tej liście.

Przyczyną braku bieżącego katalogu na tej liście są zabezpieczenia.

Powiedzmy, że jesteś rootem, idź do katalogu innego użytkownika i wpisz slzamiast ls. Jeśli bieżący katalog się znajduje PATH, powłoka spróbuje uruchomić slprogram w tym katalogu (ponieważ nie ma innego slprogramu). Żesl program może być złośliwy.

Działa z, ./ponieważ POSIX określa, że nazwa polecenia, która zawiera, /zostanie użyta bezpośrednio jako nazwa pliku, uniemożliwiając wyszukiwanie $PATH. Możesz użyć pełnej ścieżki dla tego samego efektu, ale ./jest krótszy i łatwiejszy do napisania.

EDYTOWAĆ

Ta slczęść była tylko przykładem. Katalogi w PATHsą przeszukiwane sekwencyjnie, a po dopasowaniu program jest wykonywany. Tak więc, w zależności od PATHwyglądu, wpisanie normalnego polecenia może, ale nie musi wystarczyć do uruchomienia programu w bieżącym katalogu.

cnicutar
źródło
47
Nie musisz niczego błędnie wpisywać. Użytkownik mógł właśnie pobrać złośliwy pakiet zawierający lsplik wykonywalny.
Juliano
13
Tylko uwaga dla wszystkich, którzy mówią, że jest to tylko w systemie Unix, a nie Windows, tak samo jest w Powershell - aby wykonać, musisz zrobić .\my.batitp.
manojlds,
1
@gaearon ergh, powiedziałem „nie jest pseudonimem”, kiedy to powinno być „to ściśle alias”.
Charles Duffy
4
To było bardzo pomocne wyjaśnienie. Ponad 20 lat temu, kiedy trochę pracowałem z DOS-em, myślę, że CMD sprawdziłby bieżący katalog, a PONAD ŚCIEŻKĘ, więc zachowanie Linuksa nie było tym, czego się spodziewałem, ale ma to sens.
TecBrat,
2
@cnicutar: Co ciekawe dzisiaj odkryłem, że istnieje slpolecenie o nazwie lokomotywa parowa, chociaż domyślnie niedostępne ;-)
blackSmith
51

Kiedy bash interpretuje wiersz poleceń, szuka poleceń w lokalizacjach opisanych w zmiennej środowiskowej $PATH. Aby to zobaczyć, wpisz:

echo $PATH

Będziesz miał kilka ścieżek oddzielonych dwukropkami. Jak zobaczysz, bieżącej ścieżki .zwykle nie ma $PATH. Więc Bash nie może znaleźć twojego polecenia, jeśli znajduje się w bieżącym katalogu. Możesz to zmienić, mając:

PATH=$PATH:.

Ta linia dodaje bieżący katalog, $PATHdzięki czemu możesz:

manage.py syncdb

Nie jest to zalecane, ponieważ ma problem z bezpieczeństwem, a ponadto możesz mieć dziwne zachowania, jak. zależy to od katalogu, w którym się znajdujesz :)

Uniknąć:

PATH=.:$PATH

Jak możesz „zamaskować” jakieś standardowe polecenie i otworzyć drzwi do naruszenia bezpieczeństwa :)

Tylko moje dwa centy.

neuro
źródło
42

Skrypt znajdujący się w katalogu domowym nie zostanie znaleziony, gdy powłoka spojrzy na $PATHzmienną środowiskową w celu znalezienia skryptu.

./Mówi „wygląd w bieżącym katalogu dla mojego skryptu zamiast patrząc na wszystkich katalogach określonych w $PATH”.

MDM
źródło
5

Gdy dodasz „.” zasadniczo podajesz „pełną ścieżkę” do wykonywalnego skryptu bash, więc twoja powłoka nie musi sprawdzać zmiennej PATH. Bez '.' twoja powłoka zajrzy do zmiennej PATH (którą możesz zobaczyć, uruchamiając, echo $PATHaby sprawdzić, czy wpisane polecenie mieszka w którymkolwiek z folderów PATH. Jeśli tak nie jest (jak w przypadku manage.py), to mówi nie można znaleźć pliku. Złą praktyką jest dołączanie bieżącego katalogu do PATH, co jest dość dobrze wyjaśnione tutaj: http://www.faqs.org/faqs/unix-faq/faq/part2/section- 13.html

Mark Drago
źródło
2

W systemie * nix, w przeciwieństwie do systemu Windows, bieżącego katalogu zwykle nie ma w $PATHzmiennej. Dlatego bieżący katalog nie jest przeszukiwany podczas wykonywania poleceń. Nie musisz ./uruchamiać aplikacji, ponieważ te aplikacje znajdują się w $ PATH; najprawdopodobniej są w /binlub /usr/bin.

Dezorganizacja
źródło
1

To pytanie ma już niesamowite odpowiedzi, ale chciałem dodać, że jeśli twój plik wykonywalny znajduje się na PATH, a po uruchomieniu masz bardzo różne dane wyjściowe

./executable

do tych, które dostaniesz, jeśli uciekniesz

executable

(powiedzmy, że napotykasz komunikaty o błędach z jednym, a nie drugim), problem może polegać na tym, że masz dwie różne wersje pliku wykonywalnego na swoim komputerze: jeden na ścieżce, a drugi nie.

Sprawdź to, uruchamiając

który jest wykonywalny

i

whereis executable

Naprawiło to moje problemy ... Miałem trzy wersje pliku wykonywalnego, z których tylko jedna została poprawnie skompilowana dla środowiska.

KR_Henninger
źródło
0

Uzasadnienie dla /reguły POSIX PATH

Reguła została wspomniana na stronie: Dlaczego potrzebujesz ./ (kropka-ukośnik) przed nazwą pliku wykonywalnego lub skryptu, aby uruchomić ją w trybie bash? ale chciałbym bardziej szczegółowo wyjaśnić, dlaczego uważam, że to dobry projekt.

Po pierwsze, wyraźna pełna wersja reguły to:

  • Jeśli ścieżka zawiera /(na przykład ./someprog, /bin/someprog,./bin/someprog ) CWD jest używany i ścieżka nie jest
  • jeśli ścieżka nie zawiera /(np. someprog): używana jest ŚCIEŻKA, a CWD nie

Załóżmy teraz, że działa:

someprog

szukałby:

  • względem CWD pierwszy
  • względem PATH po

Następnie, jeśli chcesz uciec /bin/someprogz dystrybucji, a zrobiłeś:

someprog

czasami to działałoby, ale innym się nie udawało, ponieważ możesz znajdować się w katalogu, który zawiera inny niepowiązany someprog program.

Dlatego wkrótce dowiesz się, że nie jest to wiarygodne, i zawsze będziesz używał ścieżek bezwzględnych, gdy chcesz użyć ŚCIEŻKI, co pokona cel ŚCIEŻKI.

Dlatego też posiadanie ścieżek względnych w ŚCIEŻCE jest naprawdę złym pomysłem. Ja patrząc na ciebie,node_modules/bin .

I odwrotnie, załóżmy, że działa:

./someprog

Wyszukiwałby:

  • względem PATH pierwszy
  • względem CWD po

Następnie, jeśli właśnie pobrałeś skrypt someprogz repozytorium git i chciałbyś go uruchomić z CWD, nigdy nie byłbyś pewien, że to byłby właściwy program, ponieważ może twoja dystrybucja ma:

/bin/someprog

który jest w TWOJEJ ŚCIEŻCE z jakiegoś pakietu, który zainstalowałeś po wypiciu za dużo po Bożym Narodzeniu w zeszłym roku.

Dlatego po raz kolejny będziesz zmuszony zawsze uruchamiać lokalne skrypty względem CWD z pełnymi ścieżkami, aby wiedzieć, co uruchamiasz:

"$(pwd)/someprog"

co byłoby również bardzo denerwujące.

Kolejną zasadą, którą możesz pokusić się o wymyślenie, byłoby:

ścieżki względne używają tylko PATH, ścieżki bezwzględne tylko CWD

ale po raz kolejny zmusza to użytkowników do korzystania ze ścieżek bezwzględnych dla skryptów innych niż PATH "$(pwd)/someprog".

/Reguła przeszukiwanie ścieżki oferuje prosty do zapamiętania rozwiązanie dotyczące problemu:

  • ukośnik: nie używaj PATH
  • bez ukośnika: tylko użyj PATH

co sprawia, że ​​bardzo łatwo jest zawsze wiedzieć, co się uruchamia, polegając na tym, że pliki w bieżącym katalogu można wyrazić jako ./somefilelub somefile, i dlatego nadaje to jednemu z nich specjalne znaczenie.

Czasami jest trochę denerwujące, że nie można szukać some/progkrewnego PATH, ale nie widzę rozsądniejszego rozwiązania tego problemu.

Ciro Santilli
źródło
-1

Jeśli skrypt nie znajduje się na ścieżce, jest to wymagane. Aby uzyskać więcej informacji, przeczytaj http://www.tldp.org/LDP/Bash-Beginners-Guide/html/sect_02_01.html

Gayan Hewa
źródło
5
... FYI, w #bash na irc.freenode.org, stale korygujemy nieporozumienia, których ludzie nauczyli się od TLDP (szczególnie Advanced Bash Guide). Dlatego kierowanie tam ludzi jest ... może nie idealne. (Nasza preferowana dokumentacja wprowadzająca to mywiki.wooledge.org/BashGuide )
Charles Duffy
-2

Wszystko ma świetną odpowiedź na pytanie, i tak, dotyczy to tylko uruchomienia go w bieżącym katalogu, chyba że podasz ścieżkę bezwzględną. Zobacz moje próbki poniżej.

Również (kropka-ukośnik) miało dla mnie sens, gdy mam polecenie w folderze podrzędnym tmp2 (/ tmp / tmp2) i używa (podwójnego ukośnika).

PRÓBA:

[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
źródło