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, что сильно отличается от успешной записи в нее и отбрасывания вывода (и это опасно!))
Если ваш hash bang is /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
}
Некоторые интерфейсы для ОС:
_NSGetExecutablePath ()
( man 3 dyld ) readlink / proc / self / exe
getexecname ()
sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
readlink / proc / curproc / exe
readlink / proc / curproc / file
GetModuleFileName ()
с hModule
= NULL
Переносимый (но менее надежный) метод - использовать argv [0]
. Хотя вызывающая программа может установить что угодно, по соглашению устанавливается либо путь к исполняемому файлу, либо имя, которое было найдено с помощью $ PATH
.
Некоторые оболочки, включая bash и ksh, устанавливают переменную среды " ] _
" на полный путь к исполняемому файлу перед его выполнением. В этом случае вы можете использовать getenv ("_")
, чтобы получить его. Однако это ненадежно, потому что не все оболочки это делают, и он может быть установлен на что угодно или остаться от родительского процесса, который не изменил его перед выполнением вашей программы.
AFAIK, не так. Также существует двусмысленность: что бы вы хотели получить в качестве ответа, если один и тот же исполняемый файл имеет несколько жестких ссылок, «указывающих» на него? (Жесткие ссылки на самом деле не «указывают», они являются одним и тем же файлом, просто в другом месте в иерархии FS.) После того, как execve () успешно выполняет новый двоичный файл, вся информация о его аргументах становится потеряно.
Если вам когда-либо приходилось поддерживать, скажем, Mac OS X, в которой нет / proc /, что ты бы сделал? Используйте #ifdefs для изолировать специфичный для платформы код (NSBundle, например)?
Да изоляция специфичного для платформы кода с помощью #ifdefs
- это традиционный способ выполнения этого.
Другой подход - иметь чистый #ifdef
без заголовка, который содержит объявления функций и помещает реализации в исходные файлы, специфичные для платформы. Например, посмотрите, как библиотека Poco C ++ делает нечто подобное для своего класса Environment .
Вы можете использовать argv [0] и проанализировать переменную среды PATH. Посмотрите: Пример программы, которая может найти себя