15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij
08.10.2024

Polecenie `which` w Linux: Kompletny przewodnik techniczny z przykładami

Polecenie `which` w Linux lokalizuje bezwzględną ścieżkę pliku wykonywalnego, skanując katalogi wymienione w zmiennej środowiskowej `PATH` i zwracając pierwsze znalezione dopasowanie. Jest to narzędzie zbliżone do POSIX, używane codziennie przez administratorów systemów, programistów i inżynierów DevOps do weryfikacji lokalizacji plików binarnych, audytu środowisk wykonawczych i debugowania konfliktów związanych z PATH.

Gdy uruchamiasz `which python3`, powłoka nie przeszukuje całego systemu plików — przechodzi jedynie przez rozdzieloną dwukropkami listę katalogów zapisaną w `$PATH`, od lewej do prawej, i zatrzymuje się na pierwszym trafieniu. To zachowanie jest zarówno jego największą zaletą, jak i najważniejszym ograniczeniem, które należy rozumieć.

Podstawowa składnia

“`bash

which [options] command_name [command_name …]

“`

  • `[options]` — Opcjonalne flagi modyfikujące zachowanie wyjścia (omówione szczegółowo poniżej).
  • `command_name` — Jedna lub więcej nazw plików wykonywalnych, które chcesz zlokalizować.

Jak działa `which` wewnętrznie

Gdy wywołujesz `which`, odczytuje on bieżącą wartość zmiennej środowiskowej `PATH`, dzieli ją według separatorów `:` i iteruje przez każdy katalog po kolei. Dla każdego katalogu sprawdza, czy istnieje plik pasujący do nazwy polecenia i czy ma ustawiony bit wykonywalności (uprawnienie `x`). Pierwsze dopasowanie jest wypisywane na standardowe wyjście.

Oznacza to, że `which` jest całkowicie zależny od bieżącego stanu `$PATH`. Jeśli Twój `PATH` jest błędnie skonfigurowany — na przykład niestandardowy katalog pojawia się po `/usr/bin` zamiast przed nim — `which` dokładnie odzwierciedli tę błędną konfigurację, co jest właśnie powodem, dla którego jest przydatny do debugowania.

Aby sprawdzić bieżący `PATH`:

“`bash

echo $PATH

Example output:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

“`

Podstawowe przypadki użycia i przykłady

Przykład 1: Lokalizowanie pojedynczego pliku wykonywalnego

Najbardziej podstawowym zastosowaniem jest znalezienie miejsca, w którym znajduje się plik binarny:

“`bash

which python3

“`

“`

/usr/bin/python3

“`

Potwierdza to, że gdy wpisujesz `python3`, system wykonuje `/usr/bin/python3`. Jeśli skompilowałeś własną wersję i umieściłeś ją w `/opt/python3.12/bin/`, ale ten katalog nie jest w `PATH`, `which` jej nie znajdzie.

Przykład 2: Zapytanie o wiele poleceń w jednym wywołaniu

Możesz przekazać wiele nazw poleceń w jednym wywołaniu, co jest wydajne podczas audytu środowiska kompilacji:

“`bash

which python3 gcc git curl wget

“`

“`

/usr/bin/python3

/usr/bin/gcc

/usr/bin/git

/usr/bin/curl

/usr/bin/usr/bin/wget

“`

Jest to szczególnie przydatne w skryptach walidacji potoków CI/CD, gdzie przed rozpoczęciem kompilacji należy potwierdzić, że wszystkie wymagane narzędzia są dostępne.

Przykład 3: Odkrywanie wszystkich instancji za pomocą `-a`

Flaga `-a` instruuje `which`, aby kontynuował wyszukiwanie po pierwszym dopasowaniu i raportował każdą instancję znalezioną we wszystkich katalogach `PATH`:

“`bash

which -a python3

“`

“`

/usr/bin/python3

/usr/local/bin/python3

“`

Jest to kluczowe w środowiskach, gdzie zainstalowanych jest wiele wersji Pythona — na przykład systemowy Python w `/usr/bin/python3` i wersja zarządzana przez pyenv w `/usr/local/bin/python3`. Plik binarny, który pojawia się jako pierwszy w `PATH`, jest tym, który zostanie wykonany. Jeśli aktywna jest niewłaściwa wersja, to wyjście dokładnie wskazuje, skąd pochodzi konflikt.

Rzeczywisty przypadek brzegowy: Na serwerach z zainstalowanym zarówno Node.js z pakietu dystrybucji, jak i Node.js zarządzanym przez nvm, `which -a node` często ujawnia dwie lub trzy konfliktujące ścieżki. Rozwiązanie tego wymaga zmiany kolejności wpisów `PATH` w `.bashrc` lub `.zshrc`, a nie ponownej instalacji oprogramowania.

Przykład 4: Zachowanie przy rozwiązywaniu aliasów

Zachowanie `which` w przypadku aliasów jest w dużej mierze zależne od powłoki i konkretnej implementacji `which` zainstalowanej w systemie.

W wielu dystrybucjach Linux `which` jest samodzielnym zewnętrznym plikiem binarnym (nie wbudowanym poleceniem powłoki), więc nie ma dostępu do tabeli aliasów bieżącej powłoki. Jednak w systemach, gdzie `which` jest zaimplementowany jako funkcja powłoki lub sam alias (powszechne w konfiguracjach zsh), może rozwiązywać aliasy:

“`bash

alias ls='ls –color=auto'

which ls

“`

W systemie zsh z `which` opartym na funkcji:

“`

ls: aliased to ls –color=auto

“`

W systemie bash z zewnętrznym plikiem binarnym `which`:

“`

/bin/ls

“`

Ta niespójność jest dobrze znanych źródłem zamieszania i jest jednym z głównych powodów, dla których doświadczeni administratorzy preferują `type` lub `command -v` w skryptach (omówione poniżej).

Przykład 5: Używanie `which` w warunkowej logice skryptów

Powszechnym wzorcem w skryptach powłoki jest używanie `which` do sprawdzenia zależności przed kontynuowaniem:

“`bash

if ! which docker > /dev/null 2>&1; then

echo "Docker is not installed or not in PATH. Aborting."

exit 1

fi

“`

Jednak bardziej przenośnym i zgodnym z POSIX podejściem dla skryptów jest `command -v`:

“`bash

if ! command -v docker > /dev/null 2>&1; then

echo "Docker not found."

exit 1

fi

“`

Różnica ma znaczenie przy pisaniu skryptów przeznaczonych do uruchamiania na wielu dystrybucjach lub powłokach.

`which` vs. `type` vs. `command -v`: Porównanie techniczne

Te trzy narzędzia odpowiadają na nakładające się, ale odrębne potrzeby. Wybranie niewłaściwego narzędzia do zadania prowadzi do subtelnych błędów, szczególnie w skryptach powłoki.

Funkcja`which``type``command -v`
Lokalizuje zewnętrzne pliki binarneTakTakTak
Rozwiązuje aliasy powłokiZależne od implementacjiTak (zawsze)Tak (zawsze)
Rozwiązuje funkcje powłokiNieTakTak
Identyfikuje wbudowane polecenia powłokiNieTakTak
Zgodny z POSIXNieTakTak
Działa niezawodnie w skryptachRyzykowneRyzykowne (wbudowane w bash)Zalecane
Format wyjściaTylko ścieżkaOpisowy ciąg znakówŚcieżka lub definicja
Przeszukuje wszystkie wpisy PATH (odpowiednik `-a`)Tak (z `-a`)Tak (z `-a`)Nie
Zewnętrzny plik binarny (nie wbudowany)TakNie (wbudowany)Nie (wbudowany)

Praktyczne wskazówki:

  • Używaj `which` interaktywnie w terminalu, gdy potrzebujesz szybkiego wyszukiwania ścieżki.
  • Używaj `type -a`, gdy chcesz zobaczyć każdą formę, jaką przyjmuje polecenie (alias, funkcja, wbudowane i plik binarny).
  • Używaj `command -v` w produkcyjnych skryptach powłoki dla przenośności POSIX.

`type` w działaniu

“`bash

type -a python3

“`

“`

python3 is /usr/bin/python3

python3 is /usr/local/bin/python3

“`

“`bash

type ls

“`

“`

ls is aliased to `ls –color=auto'

“`

`command -v` w działaniu

“`bash

command -v git

“`

“`

/usr/bin/git

“`

“`bash

command -v ll

“`

“`

ll: aliased to ls -alF

“`

Praktyczne scenariusze debugowania

Debugowanie niewłaściwej wersji Pythona

Programista zgłasza, że `python3 –version` zwraca `3.9.x`, ale zainstalował `3.11` poprzez własną kompilację. Sekwencja diagnostyczna:

“`bash

which python3 # Shows the first match

which -a python3 # Shows all matches

echo $PATH # Reveals directory ordering

ls -la /usr/local/bin/python3 # Checks if the custom build is symlinked correctly

“`

Rozwiązaniem jest prawie zawsze brakujący dowiązanie symboliczne lub problem z kolejnością `PATH` w pliku inicjalizacyjnym powłoki.

Diagnozowanie brakującego polecenia po instalacji

Jeśli `which curl` nie zwraca żadnego wyjścia, plik binarny albo nie jest zainstalowany, albo jest zainstalowany w katalogu spoza `PATH`. Rozróżnij te przypadki:

“`bash

which curl # No output = not in PATH

find /usr -name curl -type f 2>/dev/null # Search for the binary outside PATH

apt list –installed 2>/dev/null | grep curl # Check package manager

“`

Weryfikacja ścieżek narzędzi przed wdrożeniem

Podczas konfigurowania nowego środowiska VPS Hosting, standardowa lista kontrolna przed wdrożeniem powinna obejmować uruchomienie `which -a` dla każdego krytycznego pliku binarnego, od którego zależy Twoja aplikacja. Pozwala to wykryć rozbieżności środowiskowe między środowiskiem deweloperskim, testowym i produkcyjnym, zanim spowodują błędy w czasie wykonywania.

Znane ograniczenia `which`

Zrozumienie tych ograniczeń zapobiega błędnej diagnozie w złożonych środowiskach:

  • Zakres tylko `PATH`: `which` jest ślepy na wszelkie pliki wykonywalne nieosiągalne przez `$PATH`. Narzędzia zainstalowane w katalogach lokalnych użytkownika, takich jak `~/.local/bin`, zostaną znalezione tylko wtedy, gdy ten katalog jest w `PATH`.
  • Brak świadomości wbudowanych poleceń powłoki: Polecenia takie jak `cd`, `echo`, `alias` i `source` są wbudowanymi poleceniami powłoki. `which cd` nie zwróci nic lub zwróci ścieżkę do zewnętrznego pliku binarnego `cd`, który jest rzadko używany, dając mylący wynik.
  • Tabele aliasów specyficzne dla powłoki: `which` jako zewnętrzny plik binarny nie może odczytać tabeli aliasów wywołującej powłoki. Sprawia to, że jest zawodny przy introspekcji aliasów w bash.
  • Przezroczystość dowiązań symbolicznych: `which` raportuje ścieżkę dowiązania symbolicznego, a nie rozwiązany cel. Jeśli `/usr/bin/python3` jest dowiązaniem symbolicznym do `/usr/bin/python3.11`, `which python3` pokazuje `/usr/bin/python3`. Użyj `readlink -f $(which python3)`, aby rozwiązać pełny łańcuch.
  • Kontekst `sudo`: Uruchomienie polecenia z `sudo` używa `PATH` roota, który może znacznie różnić się od `PATH` zwykłego użytkownika. `which node` jako zwykły użytkownik może zwrócić inną ścieżkę niż `sudo which node`.

Zaawansowane wzorce

Rozwiązywanie pełnego łańcucha dowiązań symbolicznych

“`bash

readlink -f $(which python3)

Output: /usr/bin/python3.11

“`

Sprawdzanie uprawnień wykonywalności wraz ze ścieżką

“`bash

ls -la $(which nginx)

Output: -rwxr-xr-x 1 root root 1234567 Jan 10 2024 /usr/sbin/nginx

“`

Łączenie z `xargs` do inspekcji wsadowej

“`bash

echo "python3 gcc git" | xargs -n1 which

“`

Użycie w skryptach walidacji środowiska

Na Serwerze Dedykowanym obsługującym złożony stos aplikacji skrypt walidacji startowej może wyglądać następująco:

“`bash

#!/bin/bash

REQUIRED_BINS="nginx php-fpm mysql redis-cli composer"

MISSING=0

for bin in $REQUIRED_BINS; do

if ! command -v "$bin" > /dev/null 2>&1; then

echo "MISSING: $bin"

MISSING=$((MISSING + 1))

else

echo "OK: $bin -> $(which $bin)"

fi

done

[ "$MISSING" -gt 0 ] && exit 1

exit 0

“`

Uwagi dotyczące zachowania specyficznego dla powłoki

Zachowanie `which` nie jest jednolite we wszystkich środowiskach Linux:

  • Bash: `which` jest zazwyczaj zewnętrznym plikiem binarnym (`/usr/bin/which`). Nie widzi aliasów ani funkcji bash, chyba że zostały wyeksportowane.
  • Zsh: Wiele konfiguracji zsh dostarcza `which` jako wbudowaną funkcję powłoki, która rozwiązuje aliasy i funkcje, dzięki czemu jej wyjście jest bogatsze, ale też różni się od zachowania bash.
  • Fish shell: Fish ma własny odpowiednik `which` wbudowany, a jego system aliasów (zwany `functions`) jest obsługiwany inaczej.
  • Alpine Linux / środowiska BusyBox: Narzędzie `which` jest dostarczane przez BusyBox i może mieć ograniczony zestaw funkcji w porównaniu z pakietem GNU `which`.

Ta zmienność jest szczególnie istotna podczas zarządzania skonteneryzowanymi aplikacjami lub konfigurowania Paneli Sterowania VPS, gdzie podstawowa powłoka może różnić się od lokalnego środowiska deweloperskiego.

Kwestie bezpieczeństwa

W środowiskach wrażliwych na bezpieczeństwo `which` może być używany jako lekkie narzędzie audytowe:

  • Weryfikuj, że uprzywilejowane pliki binarne, takie jak `sudo`, `su` lub `passwd`, wskazują na oczekiwane ścieżki systemowe, a nie na katalogi zapisywalne przez użytkownika, które pojawiają się wcześniej w `PATH`.
  • Wykrywaj próby przejęcia PATH: jeśli `which ls` zwraca `/home/user/bin/ls` zamiast `/bin/ls`, możliwe, że został wstrzyknięty złośliwy plik binarny.

“`bash

Audit critical system binaries

for cmd in sudo su passwd ssh scp; do

echo "$cmd -> $(which $cmd)"

done

“`

Jest to standardowy krok podczas utwardzania serwera, który będzie hostował Certyfikaty SSL lub obsługiwał wrażliwe zakończenie TLS, gdzie integralność plików binarnych jest bezwzględnie wymagana.

Podczas zarządzania środowiskami Współdzielonego Hostingu z wieloma użytkownikami, weryfikacja, że katalogi zapisywalne przez użytkownika nie pojawiają się przed katalogami systemowymi w `PATH` żadnego użytkownika, jest ważną kontrolą bezpieczeństwa.

Macierz decyzyjna: kiedy używać którego narzędzia

ScenariuszZalecane narzędzie
Szybkie interaktywne wyszukiwanie ścieżki`which`
Skrypt: sprawdzenie czy polecenie istnieje`command -v`
Identyfikacja czy polecenie jest aliasem lub funkcją`type`
Znajdowanie wszystkich instancji w PATH`which -a` lub `type -a`
Rozwiązywanie dowiązań symbolicznych do końcowego pliku binarnego`readlink -f $(which …)`
Audyt pod kątem przejęcia PATH`which` + ręczna inspekcja PATH
Przenośne skrypty między powłokami`command -v`

Kluczowe wnioski techniczne

  • `which` przeszukuje `$PATH` od lewej do prawej i zwraca pierwsze dopasowanie pliku wykonywalnego — kolejność wpisów `PATH` bezpośrednio determinuje, który plik binarny zostanie uruchomiony.
  • Flaga `-a` jest niezbędna, gdy współistnieje wiele wersji narzędzia; nigdy nie zakładaj, że istnieje tylko jedna instancja bez sprawdzenia.
  • Nie używaj `which` w produkcyjnych skryptach powłoki — używaj `command -v` dla zgodności z POSIX i spójnego zachowania w bash, dash i zsh.
  • `which` nie może widzieć wbudowanych poleceń powłoki, funkcji ani aliasów zdefiniowanych w bieżącej sesji powłoki, gdy działa jako zewnętrzny plik binarny.
  • Zawsze uzupełniaj wynik `which` o `readlink -f`, gdy w grę wchodzą dowiązania symboliczne, aby zidentyfikować faktycznie wykonywany plik binarny.
  • W środowiskach wieloużytkownikowych lub skonteneryzowanych `PATH` różni się między użytkownikami oraz między kontekstami `sudo` i nie-`sudo` — zawsze weryfikuj we właściwym kontekście.
  • Przejęcie PATH poprzez katalogi zapisywalne przez użytkownika, dodane na początku `$PATH`, jest realnym wektorem ataku; `which` jest szybkim narzędziem pierwszej linii audytu przeciwko niemu.

Często zadawane pytania

Jaka jest różnica między `which` a `whereis`?

`which` przeszukuje tylko `$PATH` w poszukiwaniu plików wykonywalnych. `whereis` przeszukuje szerszy zestaw predefiniowanych katalogów systemowych jednocześnie w poszukiwaniu pliku binarnego, jego strony podręcznika i plików źródłowych. Używaj `whereis`, gdy potrzebujesz zlokalizować dokumentację lub źródła wraz z plikiem binarnym.

Dlaczego `which cd` nie zwraca nic?

`cd` jest wbudowanym poleceniem powłoki, a nie zewnętrznym plikiem wykonywalnym. Ponieważ `which` skanuje tylko `$PATH` w poszukiwaniu plików z uprawnieniem wykonywania, nie może znaleźć wbudowanych poleceń. Zamiast tego użyj `type cd`, które poprawnie zgłosi `cd is a shell builtin`.

Czy `which` może powiedzieć mi, która wersja programu jest zainstalowana?

Nie. `which` zwraca tylko ścieżkę. Aby uzyskać wersję, przekieruj wynik: `$(which python3) –version` lub po prostu `python3 –version`. Ścieżka z `which` pomaga potwierdzić, że odpytujesz właściwy plik binarny.

Dlaczego `which python3` zwraca inny wynik, gdy używam `sudo`?

`sudo` wykonuje polecenia ze środowiskiem roota, w tym `PATH` roota, który jest zazwyczaj bardziej restrykcyjny niż `PATH` zwykłego użytkownika. Katalogi takie jak `~/.local/bin` lub ścieżki nvm/pyenv dodane do `.bashrc` użytkownika są nieobecne w `PATH` roota. Zawsze testuj z `sudo which python3` osobno podczas debugowania wykonywania z eskalacją uprawnień.

Czy `which` jest dostępny na macOS?

Tak, macOS zawiera `which` jako część swojego środowiska użytkownika wywodzącego się z BSD. Jednak wersja macOS nie obsługuje flagi `-a` we wszystkich starszych wersjach. Na nowoczesnym macOS z Homebrew możesz mieć zainstalowany GNU `which` obok wersji systemowej. Użyj `type -a which` na macOS, aby zobaczyć, która implementacja jest aktywna.

15%

Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu:

Skills
Rozpocznij