В bash script мне нужно определить, находится ли исполняемый файл с именем foo
в PATH.
Обнаруживать, если исполняемый файл находится на пользователе PATH
Ответ 1
Вы можете использовать which
:
path_to_executable=$(which name_of_executable)
if [ -x "$path_to_executable" ] ; then
echo "It here: $path_to_executable"
fi
Ответ 2
Вы также можете использовать Bash встроенный type -P
:
help type
cmd=ls
[[ $(type -P "$cmd") ]] && echo "$cmd is in PATH" ||
{ echo "$cmd is NOT in PATH" 1>&2; exit 1; }
Ответ 3
Вы можете использовать встроенную command
, которая совместима с POSIX:
if [ -x "$(command -v "$cmd")" ]; then
echo "$cmd is in \$PATH"
fi
Проверка исполняемого файла необходима, потому что command -v
обнаруживает функции и псевдонимы, а также исполняемые файлы.
В Bash вы также можете использовать type
с -P
, которая -P
поиск по PATH
:
if type -P "$cmd" &>/dev/null; then
echo "$cmd is in \$PATH"
fi
Как уже упоминалось в комментариях, избегайте which
как это требует запуска внешнего процесса и может привести к неправильным выводам в некоторых случаях.
Ответ 4
TL; DR:
В bash
:
function is_bin_in_path {
builtin type -P "$1" &> /dev/null
}
Пример использования is_bin_in_path
:
% is_bin_in_path ls && echo "in path" || echo "not in path"
in path
Нет решений, которых следует избегать
Это не короткий ответ, потому что решение должно правильно обрабатывать:
- функции
- Псевдонимы
- Встроенные команды
- Зарезервированные слова
Примеры, которые терпят неудачу с простым type
(обратите внимание на токен после изменения type
):
$ alias foo=ls
$ type foo && echo "in path" || echo "not in path"
foo is aliased to 'ls'
in path
$ type type && echo "in path" || echo "not in path"
type is a shell builtin
in path
$ type if && echo "in path" || echo "not in path"
if is a shell keyword
in path
Обратите внимание, что в bash
, which
не является встроенным в оболочку (он находится в zsh
):
$ PATH=/bin
$ builtin type which
which is /bin/which
Этот ответ говорит, почему следует избегать использования which
:
Избегайте
which
. Мало того, что это внешний процесс, который вы запускаете для выполнения очень мало (то есть встроенныеhash
, такие какhash
,type
илиcommand
, намного дешевле), вы также можете полагаться на встроенные функции, которые действительно делают то, что вы хотите, в то время как эффекты внешних команд могут легко варьироваться от системы к системе.Зачем это нужно?
- Многие операционные системы имеют
which
, что даже не установлен статус выхода, то есть,if which foo
,foo
if which foo
не будет работать даже там, и всегда будет сообщать о том, чтоfoo
существует, даже если он не (обратите внимание, что некоторые POSIX оболочки появляются делать это тоже дляhash
).- Многие операционные системы делают
which
то нестандартное и плохое, например, изменяют вывод или даже подключаются к менеджеру пакетов.
В этом случае также избегайте command -v
Ответ, который я только что процитировал, предполагает использование command -v
, однако это не относится к текущему "является ли исполняемый файл в $PATH
?" сценарий: он потерпит неудачу именно так, как я проиллюстрировал простым type
выше.
Правильные решения
В bash
нам нужно использовать type -P
:
-P force a PATH search for each NAME, even if it is an alias, builtin, or function, and returns the name of the disk file that would be executed
В zsh
нам нужно использовать whence -P
:
-p Do a path search for name even if it is an alias, reserved word, shell function or builtin.
Для версии, которая работает в обоих {ba,z}sh
:
# True if $1 is an executable in $PATH
# Works in both {ba,z}sh
function is_bin_in_path {
if [[ -n $ZSH_VERSION ]]; then
builtin whence -p "$1" &> /dev/null
else # bash:
builtin type -P "$1" &> /dev/null
fi
}
Ответ 5
если команда -v foo; тогда фу; еще эхо "foo недоступно"; фи
Ответ 6
Используйте which
$ which myprogram
Ответ 7
Мы можем определить функцию для проверки, существует ли исполняемый файл, используя which
:
function is_executable() {
which "[email protected]" &> /dev/null
}
Функция вызывается так же, как вы вызываете исполняемый файл. "[email protected]"
гарантирует то, which
получает те же аргументы, что и функции.
&>/dev/null
гарантирует, что все, что записывается в stdout или stderr, с помощью which
перенаправляется на нулевое устройство (которое является специальным устройством, которое отбрасывает записанную в него информацию), а не записывается в stdout или stderr функцией.
Так как функция в явном виде не вернется с кодом возврата, когда он вернется, выход код последней выполняется исполняемым, который в данном случае, which
-будет код возврата функции. which
завершится с кодом, который указывает на успех, если он сможет найти исполняемый файл, указанный в аргументе функции, в противном случае с кодом выхода, который указывает на сбой. Это поведение будет автоматически воспроизведено is_executable
.
Затем мы можем использовать эту функцию для условного выполнения чего-либо:
if is_executable name_of_executable; then
echo "name_of_executable was found"
else
echo "name_of_executable was NOT found"
fi
Здесь, if
выполняет команду (команды), записанную между ним и then
которая в нашем случае is_executable name_of_executable
и выбирает ветвь для выполнения на основе кода возврата команды (ей).
С другой стороны, мы можем пропустить определение функции и использовать, which
непосредственно в if
-statement:
if which name_of_executable &> /dev/null; then
echo "name_of_executable was found"
else
echo "name_of_executable was NOT found"
fi
Тем не менее, я думаю, что это делает код немного менее читабельным.