Dlaczego muszę wpisać `. /` Przed uruchomieniem programu w bieżącym katalogu?

92

a.outDlaczego podczas uruchamiania programu C , używając terminala Ubuntu, zawsze muszę pisać ./wcześniej a.out, a nie tylko pisać a.out? Czy jest na to rozwiązanie?

Prashant Chikhalkar
źródło

Odpowiedzi:

119

Po wpisaniu nazwy programu, takiego jak a.outsystem, szuka pliku w ŚCIEŻCE. W moim systemie PATH jest ustawione na

/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games

Twój jest prawdopodobnie podobny. Aby to sprawdzić, wpisz echo $PATHw terminalu.

System przegląda te katalogi w podanej kolejności i jeśli nie może znaleźć, program generuje command not foundbłąd.

Wcześniejsze polecenie ./mówi „zapomnij o ŚCIEŻCE, chcę, żebyś przeglądał tylko bieżący katalog”.

Podobnie możesz nakazać systemowi wyszukiwanie tylko w innym określonym miejscu, poprzedzając polecenie ścieżką względną lub bezwzględną, taką jak:

../oznacza w katalogu nadrzędnym, np. ../helloposzukaj hello w katalogu nadrzędnym.

./Debug/hello: „poszukaj hellow podkatalogu Debug mojego bieżącego katalogu.”

lub /bin/ls: „szukaj lsw katalogu /bin

Domyślnie bieżący katalog nie znajduje się na ścieżce, ponieważ jest uważany za zagrożenie bezpieczeństwa. Zobacz, dlaczego tak jest. domyślnie nie na ścieżce? na Superuser, dlaczego.

Możliwe jest dodanie bieżącego katalogu do PATH, ale z powodów podanych w łączonym pytaniu nie poleciłbym tego.

Warren Hill
źródło
25
To. +1 Nie dodawaj .do PATH(jak sugerują obecnie 2 odpowiedzi) ze względu na ryzyko bezpieczeństwa wspomniane w tej odpowiedzi.
Dzień
8
Warto również zauważyć, że nie ma tu nic specjalnego ., możesz użyć pełnej lub względnej ścieżki do pliku wykonywalnego, np. /home/user/foo/a.outLub./build/a.out
tobyodavies
@tobyodavies; W rzeczywistości .jest wyjątkowy, ponieważ oznacza „mój bieżący katalog”, więc może to być dowolny katalog, w którym użytkownik znajdzie go z uprawnieniami do odczytu i wykonywania. Jest to potencjalnie bardziej niebezpieczne niż dodanie określonej w pełni kwalifikowanej ścieżki.
Warren Hill,
@WarrenHill przy rozważaniu dodania go do ścieżki, tak, jest zupełnie inaczej. Jednak pod względem składni bash .nie ma specjalnego statusu, jest to ścieżka, która równie dobrze mogłaby zacząć od /i ./blahdziałałaby równie dobrze z catlub grepjako zachęta do basha.
tobyodavies
@tobyodavies: OK Zredagowałem moją odpowiedź, aby uwzględnić Twój punkt widzenia.
Warren Hill
24

Powód tego jest prosty.

Załóżmy, że w bieżącym katalogu masz polecenie o tej samej nazwie co aplikacja. Następnie uruchomienie polecenia w powłoce spowoduje wywołanie aplikacji zamiast wbudowanego polecenia. Byłoby to zagrożenie bezpieczeństwa, jeśli nic więcej.

Wymagając ./użycia z przodu, powłoka wie, że chcesz uruchomić aplikację o podanej nazwie, a nie wbudowane polecenie o tej nazwie.

Nathan Osman
źródło
1
twoje wyjaśnienie jest mylące, istnieje różnica między wbudowanymi poleceniami w powłoce a plikami wykonywalnymi, które są dostępne poprzez zmienną PATH. W rzeczywistości twoja odpowiedź tym bardziej czytam, wydaje się bardziej niepoprawna.
Ahmed Masud,
16

./wykonuje pliki, których nie ma w twoim $PATH, raczej wykonuje plik w bieżącym katalogu (lub innym przez ./home/stefano/script.sh). Teraz PATH jest zmienną środowiskową, która zawiera wszystkie miejsca, w których bash może szukać programów wykonywalnych, bez pełnej (absolutnej) ścieżki do nich.

Ta separacja jest potrzebna, aby uniknąć uruchomienia niewłaściwego pliku. To znaczy, jeśli masz plik wywoływany lsw katalogu domowym, nie ma go w ŚCIEŻCE, dzięki czemu bash nie pomyli go z rzeczywistym ls. Zmienna PATH określa również kolejność wyszukiwania:

  • Kiedy uruchamiasz polecenie lub program próbuje wykonać wywołanie execsystemowe (specjalna metoda jądra, sposób uruchamiania programów), system szuka pliku, przechodząc przez każdy z katalogów w zmiennej PATH. Po znalezieniu programu, nawet jeśli znajduje się on w wielu katalogach, wyszukiwanie jest przerywane i uruchamiany jest pierwszy znaleziony.

Aby uruchomić plik, musisz ustawić bit wykonywalny w uprawnieniach:

  • Ponieważ jesteś już w wierszu poleceń, możesz po prostu pisać chmod +x finename.

  • Lub możesz ustawić uprawnienia, klikając plik prawym przyciskiem myszy i wybierając Właściwości :

    alternatywny tekst

Możesz teraz skopiować plik do dowolnego katalogu w PATH, aby zobaczyć, które z nich istnieją - i są ustawione dla poszczególnych użytkowników - typu echo $PATH.

stefano@3000-G530:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Jeśli utworzysz plik wykonywalny cati przeniesiesz go /usr/local/sbin, zostanie on uruchomiony zamiast właściwego cat, który znajduje się w /bin. Możesz dowiedzieć się, gdzie są twoje pliki, używając type cati whereis cat.

Stefano Palazzo
źródło
2
Należy zwrócić uwagę na jedno: jego pytanie wydaje się wskazywać, że skompilował i powiązał coś gcc, co automatycznie ustawia bit wykonania.
Nathan Osman,
12

Dlaczego musisz pisać ./przed uruchomieniem programu?

W terminalu, za każdym razem, gdy wpiszesz nazwę aplikacji, powiedzmy gedit, terminal przejdzie do niektórych (wstępnie zdefiniowanych) katalogów zawierających aplikacje (pliki binarne aplikacji). Nazwy tych katalogów są zawarte w zmiennej o nazwie PATH. Możesz zobaczyć, co jest w tej zmiennej, wykonując echo $PATH. Widzisz te katalogi oddzielone :? Są to katalogi, że terminal będzie go przeszukania, jeśli tylko wpisać gedit, nautilusalbo a.out. Jak widać, ścieżka twojego a.outprogramu nie istnieje. Kiedy to zrobisz ./a.out, mówisz terminalowi: „zajrzyj do bieżącego katalogu, uruchom a.outi nie wchodź do środka PATH.

Rozwiązanie 1

Jeśli nie chcesz pisać za ./każdym razem, musisz dodać a.outkatalog $PATH. W poniższych instrukcjach założę, że ścieżka a.outjest /path/to/programs/, ale powinieneś zmienić ją na swoją rzeczywistą ścieżkę.

  1. Po prostu dodaj następujący wiersz na końcu pliku ~/.pam_environment:

    PATH DEFAULT=${PATH}:/path/to/programs

    Źródło: Trwałe zmienne środowiskowe

  2. Wyloguj się i zaloguj ponownie. Teraz będziesz mógł uruchomić a.outbez ./żadnego katalogu.

Jeśli masz inne programy w innych katalogach, możesz po prostu dodać je do powyższej linii. Jednak radzę mieć na przykład jeden katalog o nazwie „myPrograms” i umieścić pod nim wszystkie swoje programy.

Rozwiązanie 2

Uwaga: zmień userNamena swoją rzeczywistą nazwę użytkownika Ubuntu.

Co jeśli masz inne programy, które chcesz uruchomić? I wszystkie są w różnych folderach? Cóż, „bardziej zorganizowanym” rozwiązaniem byłoby utworzenie folderu o nazwie binpod twoim katalogiem domowym i dodanie do niego dowiązań symbolicznych (skrótów). Oto jak:

  1. mkdir /home/userName/bin

    • Spowoduje to utworzenie folderu binw katalogu głównym .
  2. ln -s /path/to/programs/a.out /home/userName/bin

    • Spowoduje to utworzenie „dowiązania symbolicznego” (w skrócie) twojego a.outprogramu pod bin.
  3. Wyloguj się i zaloguj ponownie. Teraz będziesz mógł uruchomić a.outbez ./żadnego katalogu.

Teraz, gdy masz inny program gdziekolwiek indziej, powiedzmy, że program b.inna pulpicie, wszystko, co musisz zrobić, to: ln -s /home/userName/Desktop/b.in /home/userName/bina wtedy będziesz mógł go uruchomić również bez niego ./.

Uwaga: dzięki komentarzowi @ Joe podczas wykonywania kopii zapasowych linki symboliczne muszą być obsługiwane w specjalny sposób. Domyślnie rsyncwcale ich nie przetwarza, więc po przywróceniu ich nie ma.

Alaa Ali
źródło
1
Jest to przydatna sztuczka, jeśli jest używana oszczędnie. Częste korzystanie z niego sprawia, że ​​Twój system robi rzeczy, których nikt by się nie spodziewał. Ponadto, gdy wykonujesz kopie zapasowe, dowiązania symboliczne muszą być obsługiwane specjalnie. Domyślnie rsync wcale ich nie przetwarza, więc po przywróceniu ich nie ma.
Joe
1

Jak zauważył George w swojej odpowiedzi, pomaga to zauważyć, że wykonujesz plik w bieżącym katalogu roboczym ( pwd).

Pamiętam, jak dawno temu zadawałem to pytanie mojemu seniorowi, powiedział, że powinienem dodać .do mojej ścieżki, aby kiedy to zrobiłem a.out, zajrzał do bieżącego katalogu i wykonał to. W tym przypadku nie muszę tego robić ./a.out.

Ale osobiście odradzam to. Nigdy mi się to nie zdarzyło, ale jeśli znajdujesz się w obcym katalogu sieci lub coś takiego, a lsistnieje tam złośliwy plik wykonywalny o nazwie , to posiadanie .na swojej drodze jest bardzo złym pomysłem. Nie to, że często napotykasz ten problem, po prostu mówiąc.

Shrikant Sharat
źródło
ok, Stefano przyjął swoją odpowiedź, aby zawierać te informacje :)
Shrikant Sharat
3
Całkowicie zgadzam się z nie dodawaniem .do $PATH. Bardzo niebezpieczny pomysł.
Nathan Osman,
1

Oprócz innych odpowiedzi, tutaj zasadnicza część, z man bashktórej dobrze to wyjaśnia:

WYKONANIE POLECEŃ
       Po podzieleniu polecenia na słowa, jeśli powoduje proste
       polecenie i opcjonalna lista argumentów, następujące działania to
       wzięty.

       Jeśli nazwa polecenia nie zawiera ukośników, powłoka próbuje zlokalizować
       to. Jeśli istnieje funkcja powłoki o tej nazwie, jest to funkcja
       wywoływane jak opisano powyżej w FUNKCJACH. Jeśli nazwa nie pasuje do
       Funkcja szuka powłoki na liście wbudowanych powłok. Jeśli
       znaleziono dopasowanie, że wbudowane jest wywoływane.

       Jeśli nazwa nie jest ani funkcją powłoki, ani wbudowanym i nie zawiera
       ukośniki, bash przeszukuje każdy element ŚCIEŻKI w poszukiwaniu katalogu
       posiadanie pliku wykonywalnego o tej nazwie.
mook765
źródło
0

„./” ma sens, gdy uruchamiasz program, który jest ci znany i konkretny, np. Własny. Ten program musi być obecny w twoim bieżącym katalogu. „./” nie ma sensu, gdy uruchomisz standardowe polecenie, które jest gdzieś w $ PATH. Polecenie „Które polecenie uruchomić” informuje, gdzie znajduje się polecenie uruchomienia w $ PATH.

użytkownik7346
źródło
0
$ gcc hello.c -o /path/to/someplace/hello

stworzy plik wykonywalny w niektórych lokalizacjach. Jeśli ta lokalizacja znajduje się na Twojej ścieżce, będziesz mógł uruchomić plik. Możesz to zrobić, jeśli chcesz utworzyć etykietę dla akcji „skompiluj ten kod źródłowy za pomocą gcc i umieść plik wykonywalny w miejscu, które znajduje się na twojej ścieżce”

Sugerowałbym utworzenie nowego katalogu o nazwie „testbin” lub coś w tym rodzaju i umieszczenie go na swojej ścieżce, aby utrzymać istniejące katalogi ścieżek w czystości.

Jon Kiparsky
źródło
0

./eliminuje zbędne wyszukiwanie ścieżki. ./wymusza wyszukiwanie tylko w bieżącym katalogu. Jeśli nie dajemy ./wtedy będzie wyszukiwać różne ścieżki ustawione w systemie jak /usr/bin, /usr/sbin/itp

użytkownik175959
źródło
0

„./” oznacza, że ​​chcesz uruchomić plik w bieżącym katalogu, jest to skrót do wpisania całej ścieżki, na przykład:

[root@server ~]#/path/to/file/file.pl

jest taki sam jak:

[root@server file]#./file.pl

w poprzednim przykładzie przejrzałeś katalog i jego podkatalogi do lokalizacji pliku i użyłeś „./”, aby uruchomić plik w bieżącym katalogu.

poprzedni „ [root @ server ~] # / path / to / file / file.pl ” również wykona plik, jeśli leniwy jest „cd” w drodze do lokalizacji pliku.

Khaled Moustafa
źródło
-4

To bardzo proste i ma wiele zastosowań.

  1. Gdy zainstalowanych jest wiele wersji tej samej aplikacji, będzie ona dostępna w innej ścieżce, ale można utworzyć miękkie łącze do pliku binarnego /usr/bin. Na przykład Python 2.7, Python 2.6 jest zainstalowany, ale / usr / bin / python -> python2.7 / usr / local / bin / python -> python2.6

Jeśli znajdujesz się na ścieżce /usr/local/bini uruchamia się Python, zawsze wykona Python 2.7. Określenie .zajmie plik wykonywalny bieżącego folderu.

  1. .- zawsze reprezentuje wykonanie z bieżącego katalogu. I ..zawsze oznacza wykonanie z poprzedniego katalogu.
Ramjee Anna
źródło