В 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,fooif 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
Тем не менее, я думаю, что это делает код немного менее читабельным.