Ось все, про що ви ніколи не думали, що ніколи не захочете знати про це:
Підсумок
Щоб отримати ім'я виконавчого файлу у сценарії оболонки, подібному до Bourne (є кілька застережень; див. Нижче):
ls=$(command -v ls)
Щоб дізнатися, чи існує дана команда:
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
На запит інтерактивної оболонки Борна:
type ls
whichКоманда зламане спадщина від C-Shell і краще залишити в спокої в Bourne-подібних оболонках.
Використовуйте випадки
Існує різниця між пошуком цієї інформації як частини скрипту або інтерактивною підказкою оболонки.
У запиті оболонки типовим випадком використання є: ця команда поводиться дивно, чи я використовую правильну? Що саме сталося, коли я набирав текст mycmd? Чи можу я далі подивитися на те, що це таке?
У цьому випадку ви хочете знати, що робить ваша оболонка, коли ви викликаєте команду, не фактично викликаючи команду.
У сценаріях оболонок вона, як правило, зовсім інша. У скрипті оболонки немає жодної причини, чому б ви хотіли знати, де або що є командою, якщо все, що ви хочете зробити, це запустити її. Як правило, те, що ви хочете знати, - це шлях до виконуваного файлу, тому ви можете отримати більше інформації з нього (наприклад, шлях до іншого файлу щодо цього або прочитати інформацію зі вмісту виконуваного файлу на цьому шляху).
Інтерактивний, ви можете захотіти дізнатися про всіх тих my-cmdкомандах , доступних в системі, в сценаріях, рідко так.
Більшість доступних інструментів (як це часто буває) були розроблені для інтерактивного використання.
Історія
Спочатку трохи історії.
Ранні оболонки Unix до кінця 70-х років не мали жодних функцій чи псевдонімів. Лише традиційний пошук виконуваних файлів у $PATH. cshпредставив псевдоніми близько 1978 року (хоча cshвперше був випущений у 2BSDтравні 1979 року), а також обробку .cshrcдля користувачів, щоб налаштувати оболонку (кожна оболонка, як cshчитається, .cshrcнавіть коли вона не є інтерактивною, як у сценаріях).
в той час як оболонка Bourne була вперше випущена в Unix V7 на початку 1979 року, підтримка функцій була додана лише набагато пізніше (1984 в SVR2), і все одно, вона ніколи не мала rcфайлу ( .profileце налаштування вашого середовища, а не оболонки як такої ).
csh отримав набагато більшу популярність, ніж оболонка Борна, оскільки (хоча він мав жахливо синтаксис, ніж оболонка Борна), він додав багато більш зручних і приємних функцій для інтерактивного використання.
У 3BSD1980 році для користувачів було додано whichскрипт csh,csh який допоможе визначити виконуваний файл, і це навряд чи інший сценарій, який ви можете знайти, як whichу багатьох комерційних Unices сьогодні (наприклад, Solaris, HP / UX, AIX або Tru64).
Цей скрипт читає користувача ~/.cshrc(як і всі cshсценарії, якщо не викликається csh -f) та шукає вказані імена команд у списку псевдонімів та в $path(масив, який cshпідтримується на основі $PATH).
Ось, whichвийшло першою для найпопулярнішої на той час оболонки (і cshдосі була популярною до середини 90-х), що є основною причиною, чому вона задокументована в книгах і досі широко використовується.
Зауважте, що навіть для cshкористувача, цей whichскрипт csh не обов'язково дає вам потрібну інформацію. Він отримує псевдоніми, визначені в ~/.cshrc, а не ті, які ви, можливо, визначили пізніше під час запиту або, наприклад, за допомогою sourceіншого cshфайлу, і (хоча це не буде гарною ідеєю), PATHможуть бути переосмислені в ~/.cshrc.
Запустивши цю whichкоманду з оболонки Bourne, все одно буде шукати псевдоніми, визначені у вашому ~/.cshrc, але якщо його немає, оскільки ви не використовуєте csh, це все одно отримає правильну відповідь.
Подібна функціональність була додана оболонці Bourne до 1984 року в SVR2 за допомогою typeвбудованої команди. Той факт, що він вбудований (на відміну від зовнішнього сценарію) означає, що він може дати вам потрібну інформацію (певною мірою), оскільки має доступ до внутрішніх оболонок.
Початкова typeкоманда страждала від аналогічної проблеми, як і whichсценарій, оскільки вона не повертала статус виходу з ладу, якщо команда не була знайдена. Крім того, для виконуваних файлів, навпаки which, він виводить щось на зразок ls is /bin/lsзамість того, що лише /bin/lsробить його менш простим у використанні в сценаріях.
Оболонка Борна для Unix версії 8 (не випущена в дикій природі) повинна була typeперейменована в whatis. І оболонка Plan9 (колишній наступник Unix) rc(і її похідні, як akangaі es) також є whatis.
Оболонка Korn (підмножина, на якій засноване визначення POSIX sh), розроблена в середині 80-х, але не була широко доступною до 1988 року, додала багато cshфункцій (редактор рядків, псевдоніми ...) поверх оболонки Bourne . Він додав власний whenceвбудований (на додаток до type), який взяв кілька варіантів ( -vзабезпечити typeподібний багатослівний вихід і -pшукати тільки виконувані файли (не псевдоніми / функції ...)).
Одночасно з потрясінням щодо проблем з авторським правом між AT&T та Berkeley, в кінці 80-х на початку 90-х з'явилося кілька реалізацій безкоштовних програмних оболонок. Вся оболонка Almquist (зола, яка повинна бути заміною оболонки Борна в BSD), реалізація ksh (pdksh) bash(спонсорована FSF) у публічному доступі , zshз'явилася між 1989 і 1991 роками.
Еш, хоч і мала бути заміною оболонки Борна, не мала typeвбудованої системи набагато пізніше (в NetBSD 1.3 та FreeBSD 2.3), хоча й мала hash -v. OSF / 1 /bin/shмав typeвбудований модуль, який завжди повертав 0 до OSF / 1 v3.x. bashне додав, whenceале додав -pможливість typeнадрукувати шлях ( type -pяк би whence -p) і -aповідомити про всі відповідні команди. tcshзробив whichвбудований і додав whereкоманду, що діє як bash's type -a. zshмає їх усіх.
fishОболонка (2005) має typeкоманду реалізована у вигляді функції.
whichCSH сценарій тим часом був видалений з NetBSD (як це було в Tcsh вбудованої і не багато користі в інших оболонках), а функціональність додається до whereis(при виклику , як which, whereisповодиться як whichкрім того, що він тільки дивиться виконувані $PATH). У OpenBSD і FreeBSD whichтакож було змінено на написане на C, яке шукає $PATHлише команди .
Впровадження
Існують десятки реалізацій whichкоманди в різних Unices з різним синтаксисом і поведінкою.
На Linux (поруч із вбудованими в tcshта в zsh) ми знаходимо кілька реалізацій. Наприклад, в останніх системах Debian це простий скрипт оболонки POSIX, який шукає команди в $PATH.
busyboxтакож має whichкоманду.
Є, GNU whichмабуть, найбільш екстравагантний. Він намагається розширити те, що whichзробив скрипт csh, на інші оболонки: ви можете сказати йому, які ваші псевдоніми та функції, щоб він міг дати вам кращу відповідь (і я вважаю, що деякі дистрибутиви Linux встановлюють деякі глобальні псевдоніми навколо цього для того, bashщоб це зробити) .
zshмає пару операторів для розширення до шляху виконуваних файлів: оператора = розширення імені файлів та :cмодифікатора розширення історії (тут застосовано до розширення параметра ):
$ print -r -- =ls
/bin/ls
$ cmd=ls; print -r -- $cmd:c
/bin/ls
zsh, в zsh/parametersмодулі також створюється хеш-таблиця команд як commandsасоціативний масив:
$ print -r -- $commands[ls]
/bin/ls
whatisУтиліта (для одного в оболонці або плані 9 Unix V8 Bourne , крім rc/ es) насправді не пов'язана , як це тільки для документації (бази даних відбирає Whatis, тобто людина , сторінка синопсис).
whereisтакож було додано в 3BSDтой самий час, як whichніби це було написано C, а не cshі використовується для пошуку одночасно виконуваного файлу, довідкової сторінки та джерела, але не на основі поточного середовища. Отже, знову ж таки, що відповідає іншій потребі.
Тепер, на стандартній панелі, POSIX вказує команди command -vта -Vкоманди (які були необов'язковими до POSIX.2008). UNIX вказує typeкоманду (опція відсутня). Це все ( where, which, whenceне вказані в будь-якому стандарті)
До певної версії typeта вони command -vбули необов'язковими у специфікації Linux Standard Base, яка пояснює, чому, наприклад, деякі старі версії posh(хоча на основі pdkshяких були обидві) не мали жодної. command -vтакож було додано до деяких реалізацій оболонок Bourne (наприклад, на Solaris).
Статус сьогодні
На сьогоднішній день статус такий typeі command -vє всюдисущим у всіх оболонках Борна (хоча, як зазначає @jarno, зверніть увагу на застереження / помилку, bashколи вони не перебувають у режимі POSIX або деякі нащадки оболонки Алквіста нижче в коментарях). tcshце єдина оболонка, де ви б хотіли використовувати which(оскільки там немає typeі whichвбудована).
В інших , ніж оболонках tcshі zsh, whichможе сказати вам шлях даного файлу, поки немає псевдоніма або функції до того ж імені в будь-якому з наших ~/.cshrc, ~/.bashrcабо будь-якого іншого файлу запуск оболонки і не визначити $PATHв вашому ~/.cshrc. Якщо у вас визначений псевдонім або функція, він може або не може сказати вам про це, або сказати вам неправильну річ.
Якщо ви хочете дізнатися про всі команди за вказаним іменем, нічого портативного немає. Ви б використовували whereв tcshабо zsh, type -aв bashабо zsh, whence -aв ksh93 та в інших оболонках, які ви можете використовувати typeв комбінації, з which -aякою це може працювати.
Рекомендації
Отримання імені шляху до виконуваного файлу
Тепер, щоб отримати ім'я шляху виконуваного файлу в сценарії, є кілька застережень:
ls=$(command -v ls)
був би стандартним способом це зробити.
Однак є кілька питань:
- Пізнати шлях виконуваного файлу без його виконання неможливо. Все
type, which, command -v... все використовують евристики , щоб дізнатися шлях. Вони перебирають $PATHкомпоненти та знаходять перший файл без каталогу, на який ви маєте дозвіл на виконання. Однак, залежно від оболонки, коли мова йде про виконання команди, багато з них (Bourne, AT&T ksh, zsh, ash ...) просто виконають їх у порядку, $PATHпоки execveсистемний виклик не повернеться з помилкою . Наприклад, якщо вони $PATHмістять /foo:/barі ви хочете виконати ls, вони спершу спробують виконати /foo/lsабо якщо це не вдасться /bar/ls. Зараз виконання/foo/lsможе вийти з ладу, оскільки у вас немає дозволу на виконання, але також і з багатьох інших причин, наприклад, що це недійсний виконуваний файл. command -v lsповідомив би, /foo/lsякщо у вас є дозвіл на виконання /foo/ls, але запуск lsможе насправді працювати, /bar/lsякщо /foo/lsне є дійсним виконуваним файлом.
- якщо
fooвбудований або функція чи псевдонім, command -v fooповертається foo. З такими оболонками, як ash, pdkshабо zsh, він також може повернутися, fooякщо він $PATHмістить порожній рядок і fooв поточному каталозі є виконавчий файл. Є деякі обставини, коли вам може знадобитися це врахувати. Майте на увазі, наприклад, що список вбудованих файлів змінюється залежно від реалізації оболонки (наприклад, mountіноді вбудований для зайнятої скриньки sh), і, наприклад, bashможна отримувати функції з оточення.
- якщо
$PATHмістить відносні компоненти шляху (як правило, .або порожній рядок, який обоє посилається на поточний каталог, але може бути чим завгодно), залежно від оболонки, command -v cmdне може виводити абсолютний шлях. Тож шлях, який ви отримаєте під час запуску command -v, більше не буде дійсним після вас cdдесь в іншому місці.
- Анекдотичні: з ksh93 оболонки, якщо
/opt/ast/bin(хоча точний шлях може варіюватися в різних системах , я вважаю) в вас $PATH, ksh93 надаватиме кілька додаткових вбудованих команд ( chmod, cmp, cat...), але command -v chmodповернеться , /opt/ast/bin/chmodнавіть якщо цей шлях Байдуже » t існують.
Визначення, чи існує команда
Щоб дізнатися, чи дана команда існує стандартно, ви можете зробити:
if command -v given-command > /dev/null 2>&1; then
echo given-command is available
else
echo given-command is not available
fi
Де можна скористатися which
(t)csh
В cshі tcsh, у вас немає великого вибору. В tcsh, це добре, як whichце вбудовано. У cshцьому буде системна whichкоманда, яка може не робити те, що ви хочете, в кількох випадках.
знаходити команди лише в деяких оболонках
Випадок , коли це можливо , має сенс використовувати which, якщо ви хочете знати , шлях команди, ігноруючи потенційні внутрішні команди або функції оболонки в bash, csh(НЕ tcsh), dashабо Bourneсценарії оболонки, тобто снаряди , які не мають whence -p(наприклад , kshчи zsh) , command -ev(як yash), whatis -p( rc, akanga) або вбудований which(як tcshабо zsh) в системах, де whichдоступний і не є cshсценарієм.
Якщо ці умови виконані, то:
echo=$(which echo)
дасть вам шлях першого echoв $PATH(за винятком кутових випадків), незалежно від того, чи echoбуває оболонка вбудована / псевдонім / функція чи ні.
В інших оболонках вам краще:
- zsh :
echo==echoабо echo=$commands[echo]абоecho=${${:-echo}:c}
- ksh , zsh :
echo=$(whence -p echo)
- яш :
echo=$(command -ev echo)
- rc , akanga :
echo=`whatis -p echo`(остерігайся шляхів з пробілами)
- риба :
set echo (type -fp echo)
Зауважте, що якщо все, що ви хочете зробити, це запустити цю echoкоманду, вам не доведеться пройти її шлях, ви можете просто зробити:
env echo this is not echoed by the builtin echo
Наприклад, з tcsh, щоб запобігти використанню вбудованого which:
set Echo = "`env which echo`"
коли вам потрібна зовнішня команда
Інший випадок, коли ви, можливо, захочете скористатися, whichце коли вам фактично потрібна зовнішня команда. POSIX вимагає, щоб усі вбудовані оболонки (на зразок command) також були доступні у вигляді зовнішніх команд, але, на жаль, це не стосується commandбагатьох систем. Наприклад, рідко можна зустріти commandкоманду в операційних системах на базі Linux, тоді як у більшості з них є whichкоманди (правда, різні з різними параметрами та поведінкою).
Випадки, коли ви хочете, щоб зовнішня команда була, де б ви не виконували команду без виклику оболонки POSIX.
system("some command line"), popen()... функції C або різних мовах дійсно викликати оболонку для розбору цієї командного рядка, так що system("command -v my-cmd")працюють в них. Виняток з цього може бути perlоптимізацією оболонки, якщо вона не бачить спеціального символу оболонки (крім пробілу). Це стосується також оператора backtick:
$ perl -le 'print system "command -v emacs"'
-1
$ perl -le 'print system ":;command -v emacs"'
/usr/bin/emacs
0
$ perl -e 'print `command -v emacs`'
$ perl -e 'print `:;command -v emacs`'
/usr/bin/emacs
Додавання цього :;вище змушує perlвикликати там оболонку. Використовуючи which, вам не доведеться використовувати цей трюк.
whichпередбачає інтерактивний контекст оболонки. Це питання позначено тегами / переносимість. Тому я трактую питання в цьому контексті як "що використовувати замість того,whichщоб знайти перший виконуваний файл заданого імені в$PATH". Більшість відповідей та причин протиwhichспілкування з псевдонімами, вбудованими функціями та функціями, які в більшості реальних портативних скриптів оболонки викликають науковий інтерес. Локально визначені псевдоніми не успадковуються під час запуску сценарію оболонки (якщо ви не використовуєте його.).