Подтвердить что ты не робот

Обнаруживать, если исполняемый файл находится на пользователе PATH

В bash script мне нужно определить, находится ли исполняемый файл с именем foo в PATH.

4b9b3361

Ответ 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

Тем не менее, я думаю, что это делает код немного менее читабельным.