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

“`

Використання у скриптах перевірки середовища

На Виділеному сервері, що запускає складний стек застосунків, скрипт перевірки під час запуску може виглядати так:

“`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` повертає лише шлях. Щоб отримати версію, передайте результат через pipe: `$(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
Почати