Ответ
POSIX совместимый:
command -v <the_command>
Для bash
особых сред:
hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords
Объяснение
Избегайте which
. Это не только внешний процесс, который вы запускаете для выполнения очень мало (то есть встроенные функции, такие как hash
, type
или command
, значительно дешевле), вы также можете полагаться на встроенные функции, которые действительно делают то, что вы хотите, в то время как эффекты внешних команд могут легко варьироваться от системы к системе.
Зачем это нужно?
- Многие операционные системы имеют
which
, который даже не устанавливает статус выхода , то есть if which foo
даже не будет работать и всегда сообщает, что foo
существует, даже если его нет (обратите внимание, что некоторые оболочки POSIX, кажется, делают это и для hash
).
- Многие операционные системы заставляют
which
делать нестандартные и злые вещи, например, изменять вывод или даже подключаться к менеджеру пакетов.
Итак, не используйте which
. Вместо этого используйте один из них:
$ command -v foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ type foo >/dev/null 2>&1 || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
$ hash foo 2>/dev/null || { echo >&2 "I require foo but it's not installed. Aborting."; exit 1; }
(Незначительное замечание: некоторые предполагают, что 2>&-
- это то же самое 2>/dev/null
, но короче - это не соответствует действительности . 2>&-
закрывает FD 2, что вызывает ошибку в программе, когда он пытается записать в stderr, что сильно отличается от успешной записи в него и отбрасывания вывода (и опасно!))
Если ваш хэш-удар равен /bin/sh
, вам следует позаботиться о том, что говорит POSIX. Коды выхода type
и hash
не очень хорошо определены в POSIX, и hash
успешно завершается, когда команда не существует (еще не видел это с type
). Состояние выхода command
хорошо определено POSIX, так что, вероятно, наиболее безопасным является использование.
Если ваш скрипт использует bash
, правила POSIX больше не имеют значения, и оба type
и hash
становятся совершенно безопасными для использования. type
теперь имеет -P
для поиска только PATH
, а hash
имеет побочный эффект, что расположение команды будет хэшировано (для более быстрого поиска при следующем использовании), что обычно хорошо, так как вы, вероятно, проверяете его существование, чтобы реально использовать его.
В качестве простого примера, вот функция, которая запускает gdate
, если она существует, в противном случае date
:
gnudate() {
if hash gdate 2>/dev/null; then
gdate "$@"
else
date "$@"
fi
}