Как проверить, существует ли программа из скрипта Bash?

Проблема в CChild на самом деле не наследуется от CParent.

И поэтому у нее нет метода doIt, который принимает только один аргумент.

1925
задан codeforester 16 October 2018 в 04:03
поделиться

22 ответа

Ответ

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
}
2677
ответ дан Cory Klein 16 October 2018 в 04:03
поделиться

Я должен был проверить, был ли установлен git как часть развертывания нашего CI-сервера. Мой последний скрипт bash был следующим (сервер Ubuntu):

if ! builtin type -p git &>/dev/null; then
  sudo apt-get -y install git-core
fi

Надеюсь, что это поможет кому-то еще!

-1
ответ дан Greg K 16 October 2018 в 04:03
поделиться

Если вы, ребята, не можете заставить вещи выше / ниже работать и выдергивать волосы из спины, попробуйте выполнить ту же команду, используя bash -c. Достаточно взглянуть на этот сомнамбулярный бред, это то, что действительно происходит, когда вы запускаете $ (подкоманда):

Сначала. Это может дать вам совершенно другой результат.

$ command -v ls
alias ls='ls --color=auto'
$ bash -c "command -v ls"
/bin/ls

Второе. Это может вообще не дать вам результата.

$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found
1
ответ дан user619271 16 October 2018 в 04:03
поделиться

Попробуйте использовать:

test -x filename

или

[ -x filename ]

Из справочной страницы bash в разделе Условные выражения :

 -x file
          True if file exists and is executable.
20
ответ дан Hengjie 16 October 2018 в 04:03
поделиться

Я никогда не заставлял вышеуказанные решения работать на коробке, к которой у меня есть доступ. Для одного типа был установлен (делает то, что делает больше). Так что встроенная директива необходима. Эта команда работает для меня:

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi
10
ответ дан Steven Penny 16 October 2018 в 04:03
поделиться

hash foo 2>/dev/null : работает с Zsh, Bash, Dash и Ash.

type -p foo: кажется, что он работает с zsh, bash и ash (busybox), но не с dash (интерпретирует -p как аргумент).

command -v foo: работает с zsh, bash, dash, но не с ash (busybox) (-ash: command: not found).

Также обратите внимание, что builtin недоступно с ash и dash.

6
ответ дан blueyed 16 October 2018 в 04:03
поделиться

Команда which может быть полезна. человек, который

Возвращает 0, если исполняемый файл найден, 1, если он не найден или не исполняемый:

NAME

       which - locate a command

SYNOPSIS

       which [-a] filename ...

DESCRIPTION

       which returns the pathnames of the files which would be executed in the
       current environment, had its arguments been  given  as  commands  in  a
       strictly  POSIX-conformant  shell.   It does this by searching the PATH
       for executable files matching the names of the arguments.

OPTIONS

       -a     print all matching pathnames of each argument

EXIT STATUS

       0      if all specified commands are found and executable

       1      if one or more specified commands is  nonexistent  or  not  exe-
          cutable

       2      if an invalid option is specified

Приятно то, что он вычисляет если исполняемый файл доступен в той среде, в которой он запущен, - это избавляет от нескольких проблем ...

-Adam

3
ответ дан Adam Davis 16 October 2018 в 04:03
поделиться

Сценарий

#!/bin/bash

# Commands found in the hash table are checked for existence before being
# executed and non-existence forces a normal PATH search.
shopt -s checkhash

function exists() {
 local mycomm=$1; shift || return 1

 hash $mycomm 2>/dev/null || \
 printf "\xe2\x9c\x98 [ABRT]: $mycomm: command does not exist\n"; return 1;
}
readonly -f exists

exists notacmd
exists bash
hash
bash -c 'printf "Fin.\n"'

Результат

✘ [ABRT]: notacmd: command does not exist
hits    command
   0    /usr/bin/bash
Fin.
0
ответ дан ecwpz91 16 October 2018 в 04:03
поделиться

Я использую это, потому что это очень просто:

if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then echo exists;else echo "not exists";fi

или

if [ `LANG=C type example 2>/dev/null|wc -l` = 1 ];then
echo exists
else echo "not exists"
fi

Он использует встроенную оболочку и программный эхо-статус для stdout и ничего для stderr другой стороны, если команда не найдена, она отображает статус только для stderr.

0
ответ дан A.N 16 October 2018 в 04:03
поделиться

Я бы просто попытался вызвать программу, например, с помощью --version или --help и , чтобы проверить, была ли команда выполнена успешно или нет

Используется с set -e скрипт завершится, если программа не найдена, и вы получите осмысленное сообщение об ошибке:

#!/bin/bash
set -e
git --version >> /dev/null
-2
ответ дан fjk 16 October 2018 в 04:03
поделиться

Потрясающий ответ и объяснение от @lhunath. Спас мой день. Я немного расширил это. Не мог контролировать себя, разделяя это - надеясь, что это может быть полезно для кого-то. Если кто-то должен проверить (массив) нескольких программ, вот быстрый фрагмент.

Что он делает? (1) Читать массив программ. (2) Показать сообщение для неудачной программы. (3) Предложить пользователю продолжить (принудительный цикл) опции y / n для проверки остальных программ.

#!/bin/bash

proginstalldir=/full/dir/path/of/installation
progsbindir=$proginstalldir/bin
echo -e "\nMy install directory - $proginstalldir"
echo -e "My binaries directory - $progsbindir"

VerifyInstall () {
clear
myprogs=( program1 program2 program3 program4 program5 programn ); 
echo -e "\nValidation of my programs started...."
for ((i=0; i<${#myprogs[@]}; i++)) ; do 
command -v $progsbindir/${myprogs[i]} >/dev/null && echo -e "Validating....\t${myprogs[i]}\tSUCCESSFUL"  || { echo -e "Validating.... \t${myprogs[i]}\tFAILED" >&2;
while true; do 
printf "%s:  "  "ERROR.... Validation FAILED for ${myprogs[i]} !!!! Continue?"; read yn; 
case $yn in [Yy] )  echo -e "Please wait..." ; break;;
[Nn]) echo -e "\n\n#################################\n##   Validation Failed .. !!   ##\n#################################\n\n" ; exit 1; break;;
*) echo -e "\nPlease answer y or n then press Enter\n"; esac; done; >&2; }; done
sleep 2
}

VerifyInstall
-3
ответ дан Ajay Kumar 16 October 2018 в 04:03
поделиться

Здесь есть множество вариантов, но я не удивился, когда не было быстрых однострочников, это то, что я использовал в начале своих сценариев: [[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; } [[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }

это основано на выбранном здесь ответе, а другой источник (а я немного поиграюсь).

надеюсь, что это будет полезно для других.

1
ответ дан keisar 16 October 2018 в 04:03
поделиться

Я согласен с lhunath препятствовать использованию which, и его решение совершенно справедливо для пользователей BASH . Однако, чтобы быть более переносимым, вместо него следует использовать command -v:

$ command -v foo >/dev/null 2>&1 || { echo "I require foo but it's not installed.  Aborting." >&2; exit 1; }

Команда command совместима с POSIX, ее спецификация приведена здесь: http://pubs.opengroup.org /onlinepubs/9699919799/utilities/command.html

Примечание: type соответствует POSIX, но type -P - нет.

196
ответ дан Veger 16 October 2018 в 04:03
поделиться

Хэш-вариант имеет один подводный камень: например, в командной строке вы можете ввести

one_folder/process

, чтобы процесс был выполнен. Для этого родительская папка one_folder должна быть в $ PATH . Но когда вы попытаетесь хешировать эту команду, она всегда будет успешной:

hash one_folder/process; echo $? # will always output '0'
1
ответ дан anycast.cw 16 October 2018 в 04:03
поделиться
GIT=/usr/bin/git                     # STORE THE RELATIVE PATH
# GIT=$(which git)                   # USE THIS COMMAND TO SEARCH FOR THE RELATIVE PATH

if [[ ! -e $GIT ]]; then             # CHECK IF THE FILE EXISTS
    echo "PROGRAM DOES NOT EXIST."
    exit 1                           # EXIT THE PROGRAM IF IT DOES NOT
fi

# DO SOMETHING ...

exit 0                               # EXIT THE PROGRAM IF IT DOES
-1
ответ дан Da'Jour 16 October 2018 в 04:03
поделиться

Это зависит от того, хотите ли вы узнать, существует ли он в одном из каталогов в переменной $PATH или знаете ли вы его абсолютное местоположение. Если вы хотите узнать, находится ли она в переменной $PATH, используйте

if which programname >/dev/null; then
    echo exists
else
    echo does not exist
fi

, в противном случае используйте

if [ -x /path/to/programname ]; then
    echo exists
else
    echo does not exist
fi

Перенаправление на /dev/null/ в первом примере подавляет вывод which программа.

74
ответ дан dreamlax 16 October 2018 в 04:03
поделиться

Если нет внешней команды type (как само собой разумеющееся здесь ), мы можем использовать POSIX-совместимый env -i sh -c 'type cmd 1>/dev/null 2>&1':

# portable version of Bash's type -P cmd (without output on stdout)
typep() {
   command -p env -i PATH="$PATH" sh -c '
      export LC_ALL=C LANG=C
      cmd="$1" 
      cmd="`type "$cmd" 2>/dev/null || { echo "error: command $cmd not found; exiting ..." 1>&2; exit 1; }`"
      [ $? != 0 ] && exit 1
      case "$cmd" in
        *\ /*) exit 0;;
            *) printf "%s\n" "error: $cmd" 1>&2; exit 1;;
      esac
   ' _ "$1" || exit 1
}

# get your standard $PATH value
#PATH="$(command -p getconf PATH)"
typep ls
typep builtin
typep ls-temp

По крайней мере в Mac OS X 10.6.8 с использованием Bash 4.2.24 (2) command -v ls не соответствует перемещению /bin/ls-temp.

2
ответ дан Community 16 October 2018 в 04:03
поделиться

Проверка на наличие нескольких зависимостей и информирование конечных пользователей о состоянии

for cmd in latex pandoc; do
  printf '%-10s' "$cmd"
  if hash "$cmd" 2>/dev/null; then
    echo OK
  else
    echo missing
  fi
done

Пример вывода:

latex     OK
pandoc    missing

Настройте 10 на максимальную длину команды , Не автоматический, потому что я не вижу не многословного способа POSIX сделать это: Как выровнять столбцы разделенной пробелами таблицы в Bash?

8
ответ дан Ciro Santilli 新疆改造中心996ICU六四事件 16 October 2018 в 04:03
поделиться

Почему бы не использовать Bash builtins, если Вы можете?

which programname

...

type -P programname
4
ответ дан 22 November 2019 в 19:59
поделиться

Принятие Вас уже применяет безопасные методы оболочки: https://sipb.mit.edu/doc/safe-shell /

set -eu -o pipefail
shopt -s failglob

./dummy --version 2>&1 >/dev/null

Это предполагает, что команда может быть вызвана таким способом, которым это (почти) ничего не делает, как создание отчетов о его версии или показ справки.

, Если эти dummy команда не найдена выходы удара со следующей ошибкой...

./my-script: line 8: dummy: command not found

Это является более полезным и менее подробным, чем другой command -v (и подобным), ответы, потому что сообщение об ошибке автоматически сгенерированный и также содержит соответствующий номер строки.

-1
ответ дан 22 November 2019 в 19:59
поделиться

Для тех, кто заинтересован, ни одна из методологий выше не работает, если вы хотите обнаружить установленную библиотеку. Я представляю, что вы остались либо с физически проверкой путь (потенциально для файлов заголовков и такие), или что-то вроде этого (если вы находитесь на дистрибутиве на основе Debian):

dpkg --status libdb-dev | grep -q not-installed

if [ $? -eq 0 ]; then
    apt-get install libdb-dev
fi

, как вы можете видеть из вышеперечисленного, A "0 «Ответ из запроса означает, что пакет не установлен. Это функция «GREP» - «0» означает, что было обнаружено совпадение, «1» означает, что совпадение не найдено.

3
ответ дан 22 November 2019 в 19:59
поделиться

Я не мог получить один из решений для работы, но после редактирования это немного я подошел с этим. Который работает для меня:

dpkg --get-selections | grep -q linux-headers-$(uname -r)

if [ $? -eq 1 ]; then
        apt-get install linux-headers-$(uname -r)
fi
-3
ответ дан 22 November 2019 в 19:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: