15%

Спести 15% на всички хостинг услуги

Тествай уменията си и получи Отстъпка за всеки хостинг план

Използвайте код:

Skills
За начало
08.10.2024

Командата `which` в Linux: Пълно техническо ръководство с примери

Командата `which` в Linux открива абсолютния път на изпълним файл, като сканира директориите, изброени в променливата на средата `PATH`, и връща първото съвпадение. Това е POSIX-съвместима помощна програма, използвана ежедневно от системни администратори, разработчици и DevOps инженери за проверка на местоположенията на двоичните файлове, одит на среди за изпълнение и отстраняване на конфликти, свързани с PATH.

Когато изпълните `which python3`, обвивката не претърсва цялата файлова система — тя обхожда само разделения с двоеточие списък от директории, съхранен в `$PATH`, отляво надясно, и спира при първото съвпадение. Това поведение е едновременно най-голямото му предимство и най-важното ограничение, което трябва да се разбере.

Основен синтаксис

“`bash

which [options] command_name [command_name …]

“`

  • `[options]` — Незадължителни флагове, които променят поведението на изхода (разгледани подробно по-долу).
  • `command_name` — Едно или повече имена на изпълними файлове, които искате да намерите.

Как работи `which` вътрешно

Когато извикате `which`, той чете текущата стойност на променливата на средата `PATH`, разделя я по разделители `:` и итерира през всяка директория по ред. За всяка директория проверява дали съществува файл, съответстващ на името на командата, и дали има зададен бит за изпълнение (разрешение `x`). Първото съвпадение се отпечатва на стандартния изход.

Това означава, че `which` е изцяло зависим от текущото състояние на `$PATH`. Ако вашият `PATH` е неправилно конфигуриран — например, персонализирана директория се появява след `/usr/bin` вместо преди него — `which` ще отрази точно тази неправилна конфигурация, което е именно причината да е полезен за отстраняване на грешки.

За да прегледате текущия си `PATH`:

“`bash

echo $PATH

Example output:

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

“`

Основни случаи на употреба и примери

Пример 1: Намиране на единичен изпълним файл

Най-основната употреба е намирането на местоположението на двоичен файл:

“`bash

which python3

“`

“`

/usr/bin/python3

“`

Това потвърждава, че когато въведете `python3`, системата изпълнява `/usr/bin/python3`. Ако сте компилирали персонализирана версия и сте я поставили в `/opt/python3.12/bin/`, но тази директория не е в `PATH`, `which` няма да я намери.

Пример 2: Заявка за множество команди наведнъж

Можете да подадете множество имена на команди в едно извикване, което е ефективно при одит на среда за изграждане:

“`bash

which python3 gcc git curl wget

“`

“`

/usr/bin/python3

/usr/bin/gcc

/usr/bin/git

/usr/bin/curl

/usr/bin/usr/bin/wget

“`

Това е особено полезно в скриптове за валидиране на CI/CD конвейери, където трябва да потвърдите, че всички необходими инструменти са налични преди началото на изграждането.

Пример 3: Намиране на всички екземпляри с `-a`

Флагът `-a` указва на `which` да продължи търсенето след първото съвпадение и да докладва всеки намерен екземпляр в директориите на `PATH`:

“`bash

which -a python3

“`

“`

/usr/bin/python3

/usr/local/bin/python3

“`

Това е от съществено значение в среди, където са инсталирани множество версии на Python — например, системен Python на `/usr/bin/python3` и версия, управлявана от pyenv, на `/usr/local/bin/python3`. Двоичният файл, който се появява пръв в `PATH`, е този, който се изпълнява. Ако е активна грешната версия, този изход ви показва точно откъде произлиза конфликтът.

Реален граничен случай: На сървъри, работещи едновременно с Node.js от дистрибуцията и Node.js, управляван от nvm, `which -a node` често разкрива два или три конфликтни пътя. Разрешаването на това изисква пренареждане на записите в `PATH` в `.bashrc` или `.zshrc`, а не преинсталиране на софтуера.

Пример 4: Поведение при разрешаване на псевдоними

Поведението на `which` с псевдоними зависи силно от обвивката и конкретната реализация на `which`, инсталирана в системата.

В много Linux дистрибуции `which` е самостоятелен външен двоичен файл (не вграден в обвивката), така че няма достъп до таблицата с псевдоними на текущата обвивка. Въпреки това, в системи, където `which` е реализиран като функция на обвивката или самият той е псевдоним (обичайно в конфигурации на zsh), той може да разрешава псевдоними:

“`bash

alias ls='ls –color=auto'

which ls

“`

В zsh система с `which` базиран на функция:

“`

ls: aliased to ls –color=auto

“`

В bash система с външния двоичен файл `which`:

“`

/bin/ls

“`

Тази непоследователност е добре известен източник на объркване и е една от основните причини опитните администратори да предпочитат `type` или `command -v` в скриптове (разгледано по-долу).

Пример 5: Използване на `which` в условна логика на скриптове

Обичаен шаблон в скриптове на обвивката е използването на `which` за проверка на зависимост преди продължаване:

“`bash

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

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

exit 1

fi

“`

Въпреки това, по-преносимият и POSIX-съвместим подход за скриптове е `command -v`:

“`bash

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

echo "Docker not found."

exit 1

fi

“`

Разграничението е важно при писане на скриптове, предназначени да работят в множество дистрибуции или обвивки.

`which` срещу `type` срещу `command -v`: Техническо сравнение

Тези три инструмента адресират припокриващи се, но различни нужди. Изборът на грешния за задачата води до фини грешки, особено в скриптове на обвивката.

Функция`which``type``command -v`
Намиране на външни двоични файловеДаДаДа
Разрешаване на псевдоними на обвивкатаЗависи от реализациятаДа (винаги)Да (винаги)
Разрешаване на функции на обвивкатаНеДаДа
Идентифициране на вградени команди на обвивкатаНеДаДа
POSIX-съвместимНеДаДа
Работи надеждно в скриптовеРискованоРисковано (вграден в bash)Препоръчително
Формат на изходаСамо пътОписателен низПът или дефиниция
Претърсване на всички записи в PATH (еквивалент на `-a`)Да (с `-a`)Да (с `-a`)Не
Външен двоичен файл (не вграден)ДаНе (вграден)Не (вграден)

Практически насоки:

  • Използвайте `which` интерактивно в терминала, когато ви е необходимо бързо намиране на път.
  • Използвайте `type -a`, когато искате да видите всяка форма, която приема дадена команда (псевдоним, функция, вграден и двоичен файл).
  • Използвайте `command -v` в производствени скриптове на обвивката за POSIX преносимост.

`type` в действие

“`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` в действие

“`bash

command -v git

“`

“`

/usr/bin/git

“`

“`bash

command -v ll

“`

“`

ll: aliased to ls -alF

“`

Практически сценарии за отстраняване на грешки

Отстраняване на грешки при грешна версия на Python

Разработчик съобщава, че `python3 –version` връща `3.9.x`, но той е инсталирал `3.11` чрез персонализирана компилация. Диагностичната последователност:

“`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

“`

Поправката почти винаги е или липсваща символна връзка, или проблем с наредбата на `PATH` в инициализационния файл на обвивката.

Диагностициране на липсваща команда след инсталация

Ако `which curl` не връща изход, двоичният файл или не е инсталиран, или е инсталиран в директория извън `PATH`. Разграничете тези случаи:

“`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

“`

Проверка на пътищата на инструментите преди внедряване

При конфигуриране на нова среда за VPS Хостинг, стандартният контролен списък преди внедряване трябва да включва изпълнение на `which -a` за всеки критичен двоичен файл, от който зависи вашето приложение. Това улавя разминаванията в средата между разработка, тестване и производство, преди да причинят грешки по време на изпълнение.

Известни ограничения на `which`

Разбирането на тези ограничения предотвратява погрешна диагноза в сложни среди:

  • Обхват само на `PATH`: `which` е сляп за всеки изпълним файл, недостъпен чрез `$PATH`. Инструменти, инсталирани в локални за потребителя директории като `~/.local/bin`, ще бъдат намерени само ако тази директория е в `PATH`.
  • Без осведоменост за вградените команди на обвивката: Команди като `cd`, `echo`, `alias` и `source` са вградени в обвивката. `which cd` ще върне нищо или път към външен двоичен файл `cd`, който рядко се използва, давайки подвеждащ резултат.
  • Таблици с псевдоними, специфични за обвивката: `which` като външен двоичен файл не може да чете таблицата с псевдоними на извикващата обвивка. Това го прави ненадежден за интроспекция на псевдоними в bash.
  • Прозрачност на символните връзки: `which` докладва пътя на символната връзка, а не разрешената цел. Ако `/usr/bin/python3` е символна връзка към `/usr/bin/python3.11`, `which python3` показва `/usr/bin/python3`. Използвайте `readlink -f $(which python3)` за разрешаване на пълната верига.
  • Контекст на `sudo`: Изпълнението на команда с `sudo` използва `PATH` на root, който може да се различава значително от `PATH` на вашия потребител. `which node` като обикновен потребител може да върне различен път от `sudo which node`.

Разширени шаблони

Разрешаване на пълната верига от символни връзки

“`bash

readlink -f $(which python3)

Output: /usr/bin/python3.11

“`

Проверка на разрешенията за изпълнение заедно с пътя

“`bash

ls -la $(which nginx)

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

“`

Комбиниране с `xargs` за пакетна инспекция

“`bash

echo "python3 gcc git" | xargs -n1 which

“`

Използване в скриптове за валидиране на средата

На Dedicated сървър, работещ с комплексен стек от приложения, скрипт за валидиране при стартиране може да изглежда така:

“`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

“`

Бележки за поведението, специфично за обвивката

Поведението на `which` не е еднакво в различните Linux среди:

  • Bash: `which` обикновено е външен двоичен файл (`/usr/bin/which`). Той не вижда псевдонимите или функциите на bash, освен ако не са експортирани.
  • Zsh: Много конфигурации на zsh включват `which` като вградена функция на обвивката, която разрешава псевдоними и функции, правейки изхода му по-богат, но и различен от поведението на bash.
  • Fish shell: Fish има свой собствен вграден еквивалент на `which`, а системата му за псевдоними (наречена `functions`) се обработва по различен начин.
  • Alpine Linux / BusyBox среди: Помощната програма `which` се предоставя от BusyBox и може да има намален набор от функции в сравнение с пакета GNU `which`.

Тази вариабилност е особено важна при управление на контейнеризирани приложения или конфигуриране на VPS контролни панели, където основната обвивка може да се различава от вашата локална среда за разработка.

Съображения за сигурност

В среди, чувствителни към сигурността, `which` може да се използва като лек инструмент за одит:

  • Проверете дали привилегировани двоични файлове като `sudo`, `su` или `passwd` се разрешават към очакваните системни пътища, а не към директории с права за запис от потребителя, намиращи се по-рано в `PATH`.
  • Откривайте опити за отвличане на PATH: ако `which ls` връща `/home/user/bin/ls` вместо `/bin/ls`, може да е бил инжектиран злонамерен двоичен файл.

“`bash

Audit critical system binaries

for cmd in sudo su passwd ssh scp; do

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

done

“`

Това е стандартна стъпка при втвърдяване на сървър, който ще хоства SSL сертификати или ще обработва чувствително TLS прекратяване, където целостта на двоичните файлове е задължителна.

При управление на среди за Споделен уеб хостинг с множество потребители, проверката дали директории с права за запис от потребителя не се появяват преди системните директории в `PATH` на никой потребител е важен контрол за сигурност.

Матрица за решения: Кога да използвате кой инструмент

СценарийПрепоръчителен инструмент
Бързо интерактивно намиране на път`which`
Скрипт: проверка дали съществува команда`command -v`
Идентифициране дали командата е псевдоним или функция`type`
Намиране на всички екземпляри в PATH`which -a` или `type -a`
Разрешаване на символни връзки до крайния двоичен файл`readlink -f $(which …)`
Одит за отвличане на PATH`which` + ръчна инспекция на PATH
Преносими скриптове за различни обвивки`command -v`

Технически основни изводи

  • `which` претърсва `$PATH` отляво надясно и връща първото съвпадение на изпълним файл — наредбата на записите в `PATH` директно определя кой двоичен файл се изпълнява.
  • Флагът `-a` е от съществено значение, когато съществуват множество версии на инструмент; никога не приемайте, че съществува само един екземпляр, без да проверите.
  • Не използвайте `which` в производствени скриптове на обвивката — използвайте `command -v` за POSIX съответствие и последователно поведение в bash, dash и zsh.
  • `which` не може да вижда вградени команди на обвивката, функции или псевдоними, дефинирани в текущата сесия на обвивката, когато работи като външен двоичен файл.
  • Винаги следвайте резултата от `which` с `readlink -f`, когато са включени символни връзки, за да идентифицирате действителния изпълняван двоичен файл.
  • В многопотребителски или контейнеризирани среди, `PATH` се различава между потребителите и между контекстите `sudo` и не-`sudo` — винаги проверявайте в правилния контекст.
  • Отвличането на PATH чрез директории с права за запис от потребителя, добавени в началото на `$PATH`, е реален вектор за атака; `which` е бърз инструмент за одит от първа линия срещу него.

Често задавани въпроси

Каква е разликата между `which` и `whereis`?

`which` претърсва само `$PATH` за изпълними файлове. `whereis` претърсва по-широк набор от предварително дефинирани системни директории за двоичния файл, неговата страница с ръководство и изходните му файлове едновременно. Използвайте `whereis`, когато трябва да намерите документация или изходен код заедно с двоичния файл.

Защо `which cd` не връща нищо?

`cd` е вградена команда на обвивката, а не външен изпълним файл. Тъй като `which` сканира само `$PATH` за файлове с разрешение за изпълнение, той не може да намери вградени команди. Използвайте вместо това `type cd`, който правилно ще докладва `cd is a shell builtin`.

Може ли `which` да ми каже коя версия на програмата е инсталирана?

Не. `which` връща само пътя. За да получите версията, пренасочете резултата: `$(which python3) –version` или просто `python3 –version`. Пътят от `which` ви помага да потвърдите, че заявявате правилния двоичен файл.

Защо `which python3` връща различен резултат, когато използвам `sudo`?

`sudo` изпълнява команди със средата на root, включително `PATH` на root, който обикновено е по-ограничителен от `PATH` на обикновен потребител. Директории като `~/.local/bin` или пътища на nvm/pyenv, добавени към `.bashrc` на потребителя, отсъстват от `PATH` на root. Винаги тествайте с `sudo which python3` отделно при отстраняване на грешки при изпълнение с повишени привилегии.

Налично ли е `which` на macOS?

Да, macOS включва `which` като част от своя потребителски слой, производен от BSD. Въпреки това, версията за macOS не поддържа флага `-a` във всички по-стари версии. На съвременен macOS с Homebrew може да имате инсталиран GNU `which` заедно със системната версия. Използвайте `type -a which` на macOS, за да видите коя реализация е активна.

15%

Спести 15% на всички хостинг услуги

Тествай уменията си и получи Отстъпка за всеки хостинг план

Използвайте код:

Skills
За начало