Как мне проверить, существует ли приложение в $ PATH?

19

Я пытаюсь написать все свои shсценарии запуска / env для работы с таким большим количеством СУХОГО и столько: «работает на каждом * nix, к которому я клонирую», насколько это возможно. Это означает, что, если я попытаюсь запустить код, которого нет, код завершится неудачно. Для этого мне нужно иметь возможность проверить, существуют ли программы. Я знаю, как проверить, существует ли файл, но я не уверен, как проверить, является ли приложение исполняемым в пути. Я бы предпочел использовать $ PATH, так как некоторые из них должны работать с arch, ubuntu и centos. Некоторые из них могут быть установлены в моем домашнем каталоге, в системах, где у меня нет root, другие могут не быть установлены, а другие все же могут быть установлены по системным путям.

xenoterracide
источник
2
Этот SO ответ - тот, который я добавил в закладки для таких вопросов.
jw013

Ответы:

19

Использование type commandname. Возвращает true, если commandnameвыполняется что-либо: псевдоним, функция, встроенная или внешняя команда (ищется в $PATH). В качестве альтернативы используйте use, command commandnameкоторый возвращает true, если commandnameэто встроенная или внешняя команда (ищется в $PATH).

exists () {
  type "$1" >/dev/null 2>/dev/null
}

Есть несколько вариантов sh (определенно pre-POSIX; я знаю о /bin/shOSF1 ≤3.x и некоторых версиях оболочки Almquist, обнаруженных в ранних версиях NetBSD и нескольких дистрибутивах Linux 20-го века), где typeвсегда возвращается 0 или нет существует. Я не думаю, что какие-либо системы поставлялись с ними в этом тысячелетии. Если вы когда-либо сталкивались с ними, вот функция, которую вы можете использовать для поиска $PATHвручную:

exists () { (
    IFS=:
    for d in $PATH; do
      if test -x "$d/$1"; then return 0; fi
    done
    return 1
) }

Эта функция обычно полезна, если вы хотите исключить встроенные модули и функции и найти имя в $PATH. Большинство оболочек имеют встроенные средства для этого, command -vхотя это относительно недавнее дополнение к POSIX (все еще необязательное для POSIX: 2004). Это в основном дружественная для программиста версия type: она печатает полный путь к исполняемому файлу $PATH, пустое имя для встроенной функции или функции и определение псевдонима для псевдонима.

exists_in_path () {
  case $(command -v -- "$1") in
    /*) return 0;;
    alias\ *) return 1;; # alias
    *) return 1;; # built-in or function
  esac
}

Ksh, bash и zsh также должны type -pискать только исполняемые файлы в $PATH. Обратите внимание, что в bash статус возврата type -p fooравен 0, если fooэто встроенная функция или функция; Если вы хотите проверить на исполняемый файл в $PATH, вы должны убедиться, что вывод не пустой. type -pне в POSIX; например, у пепла Debian (который есть /bin/shв Ubuntu) его нет.

Жиль "ТАК - перестань быть злым"
источник
@ Жиль, это (или что-то подобное) if [ type keychain ]; thenне будет работать? Я получаю ошибку, /home/xenoterracide/.zshrc:84: parse error: condition expected: typeя полагаю, я мог бы написать, что функция существует ... Я просто подумал, что это может быть проще в некотором смысле ...
xenoterracide
@xenoterracide: Сними скобки!
Жиль "ТАК - перестань быть злым"
Я думаю, что вы ищете if type $APP >/dev/null 2>/dev/null; then ...Вы не хотите [].
Стивен D
4
Бах, я знал, что должен был освежиться. Снова побежден Жилем!
Стивен D
type -pесли вы специально ищете команду в $PATH(не псевдонимы или функции или встроенные).
ephemient
1

Если вы ищете только внешние программы, вы также можете использовать какие. Не знаю, насколько это портативно.

Ким
источник
3
Теоретически, он менее переносим, ​​чем typeили command; whichнапример, не в POSIX. На практике whichон существует почти везде, но в некоторых местах (где он реализован в виде сценария csh) он использует другой путь (из-за .cshrc), что противоречит цели.
Жиль "ТАК - перестань быть злым"