Вот все, о чем вы никогда не думали, что никогда не захотите узнать об этом:
Резюме
Чтобы получить путь к исполняемому файлу в 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
стала намного более популярной, чем оболочка Bourne, поскольку (хотя она имела ужасно худший синтаксис, чем оболочка Bourne), она добавила множество более удобных и приятных функций для интерактивного использования.
В 3BSD
1980 году для пользователей был добавлен 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
что делает его менее простым в использовании в скриптах.
В оболочке Bourne версии 8 Unix (не выпущенной в дикой природе) ее type
встроенное имя было переименовано whatis
. И оболочка Plan9 (некогда преемник Unix) rc
(и ее производные, такие как akanga
и es
) также имеют whatis
.
Оболочка Korn (подмножество, на котором основано определение POSIX sh), разработанная в середине 80-х годов, но не получившая широкого распространения до 1988 года, добавила многие csh
функции (редактор строк, псевдонимы ...) поверх оболочки Bourne. , Он добавил свою собственную whence
встроенную функцию (в дополнение к type
), которая приняла несколько опций ( -v
для обеспечения type
подробного вывода -подобного вывода и -p
поиска только исполняемых файлов (не псевдонимов / функций ...)).
Совсем случайно, в связи с проблемами авторского права между AT & T и Беркли, в конце 80-х начале 90-х годов появилось несколько реализаций оболочки свободного программного обеспечения . Вся оболочка Almquist (пепел, которая должна быть заменой оболочки Bourne в BSD), общественная реализация ksh (pdksh) bash
(спонсируемая FSF), была выпущена zsh
в период между 1989 и 1991 годами.
У Ash, хотя и предназначенного для замены оболочки Bourne, не было 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
команду реализована в виде функции.
Тем which
временем сценарий csh был удален из NetBSD (поскольку он был встроен в tcsh и не очень используется в других оболочках), а функциональность была добавлена к нему whereis
(когда вызывается как which
, whereis
ведет себя как, which
за исключением того, что он просматривает только исполняемые файлы $PATH
). В OpenBSD и FreeBSD which
также был изменен на тот, что написан на C, который ищет только команды $PATH
.
Реализации
Существуют десятки реализаций which
команды в различных Unices с разным синтаксисом и поведением.
В Linux (кроме встроенных в tcsh
and 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
вездесущ во всех оболочках, похожих на Bourne (хотя, как отмечает @jarno, обратите внимание на caveat / bug, bash
когда он не в режиме POSIX или некоторые потомки оболочки Almquist ниже в комментариях). 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
он не является допустимым исполняемым файлом.
- if
foo
является встроенной функцией или функцией или псевдонимом, command -v foo
возвращает foo
. С некоторыми оболочками, такими как ash
, pdksh
или zsh
, он также может возвращать, foo
если $PATH
включает пустую строку и foo
в текущем каталоге есть исполняемый файл. Есть некоторые обстоятельства, когда вам может понадобиться принять это во внимание. Имейте в виду, например, что список встроенных функций зависит от реализации оболочки (например, mount
иногда встроен для busybox 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
даже если этот путь Безразлично» не существует.
Определение, существует ли команда
Чтобы узнать, существует ли данная команда стандартно, вы можете сделать:
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
(like yash
), whatis -p
( rc
, akanga
) или встроенный which
(like tcsh
или zsh
) в системах, где which
доступен и не является csh
сценарием.
Если эти условия соблюдены, то:
echo=$(which echo)
даст вам путь к первому echo
входу $PATH
(за исключением угловых случаев), независимо от того, является ли echo
также встроенная оболочка / псевдоним / функция или нет.
В других оболочках вы бы предпочли:
- zsh :
echo==echo
или echo=$commands[echo]
илиecho=${${:-echo}:c}
- кш , зш :
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
что оптимизируется оболочка, если она не видит никаких специальных символов оболочки (кроме пробела). Это также относится к его оператору обратного вызова:
$ 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
псевдонимов, встроенных функций и функций, которые в большинстве реальных переносимых сценариев оболочки представляют только академический интерес. Локально определенные псевдонимы не наследуются при запуске сценария оболочки (если вы его не используете.
).