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


2212

Как бы я проверил, что программа существует, таким образом, что либо вернет ошибку и выйдет, либо продолжит работу со сценарием?

Кажется, это должно быть легко, но это меня озадачило.


Что такое "программа"? Включает ли он функции и псевдонимы? whichвозвращает истину за это. typeбез аргументов дополнительно вернет true для зарезервированных слов и встроенных команд оболочки. Если «программа» означает «исполняемый в $PATH», то посмотрите этот ответ .
Том Хейл

Ответы:


3056

Ответ

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, что сильно отличается от успешной записи в нее и отбрасывания вывода (и опасно!))

Если у вас есть хэш-бэнг, /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
}

35
@Geert: часть &> / dev / null скрывает сообщение type, которое выдается, когда foo не существует. > & 2 на эхо-сигнале обеспечивает отправку сообщения об ошибке в стандартную ошибку вместо стандартного вывода; потому что это соглашение. Они оба появляются на вашем терминале, но стандартная ошибка определенно является предпочтительным выходом для сообщений об ошибках и неожиданных предупреждений.
лунат

5
флаг -P не работает в 'sh', например stackoverflow.com/questions/2608688/…
momeara

130
Для тех, кто не знаком с «продвинутым» перенаправлением ввода / 2>&- вывода в bash: 1) («закрыть дескриптор выходного файла 2», который является stderr), имеет тот же результат, что и 2> /dev/null; 2) >&2ярлык для 1>&2, который вы можете распознать как «перенаправить стандартный вывод в stderr». Для получения дополнительной информации см. Страницу перенаправления ввода-вывода Advanced Bash Scripting Guide .
mikewaters

9
@mikewaters АБС выглядит довольно продвинутым и описывает широкий диапазон функциональных возможностей командной строки bash и non-bash, но во многих аспектах он очень небрежен и не следует хорошей практике. У меня недостаточно места в этом комментарии, чтобы написать рецензию; но я могу вставить несколько случайных примеров BAD кода: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{для а seq $BEGIN $END}}, ... Многие пытались связаться с авторами и предложить улучшения , но это не вики и запросы высадились на глухие уши.
13

56
@mikewaters 2>&-это не то же самое, что 2>/dev/null. Первый закрывает дескриптор файла, а второй просто перенаправляет его на /dev/null. Вы можете не увидеть ошибку, потому что программа пытается сообщить вам на stderr, что stderr закрыт.
nyuszika7h

577

Ниже представлен переносимый способ проверить, существует ли команда $PATH и является ли она исполняемой:

[ -x "$(command -v foo)" ]

Пример:

if ! [ -x "$(command -v git)" ]; then
  echo 'Error: git is not installed.' >&2
  exit 1
fi

Проверка исполняемого файла необходима, потому что bash возвращает неисполняемый файл, если в нем не найдено исполняемого файла с таким именем $PATH.

Также обратите внимание, что если ранее не существует исполняемого файла с тем же именем, что и у исполняемого файла $PATH, dash возвращает первый, даже если последний будет выполнен. Это ошибка, которая нарушает стандарт POSIX. [ Отчет об ошибке ] [ Стандарт ]

Кроме того, произойдет сбой, если искомая команда была определена как псевдоним.


4
Будет ли command -vпуть даже для неисполняемого файла? То есть -x действительно нужен?
einpoklum

5
@einpoklum -xпроверяет, является ли файл исполняемым, и это был вопрос.
Кен Шарп

3
@KenSharp: Но это кажется излишним, поскольку commandсамо по себе будет проверять его исполняемость - не так ли?
einpoklum

13
@einpoklum Да, это необходимо. На самом деле, даже это решение может сломаться в одном крайнем случае. Спасибо, что обратили на это мое внимание. dash, bash и zsh пропускают неисполняемые файлы $PATHпри выполнении команды. Тем не менее, поведение command -vочень противоречиво. В dash он возвращает первый соответствующий файл $PATH, независимо от того, исполняемый он или нет. В bash он возвращает первое совпадение исполняемого файла $PATH, но если его нет, он может вернуть неисполняемый файл. А в zsh он никогда не вернет неисполняемый файл.
nyuszika7h

5
Насколько я могу судить, dashединственный из этих трех не поддерживает POSIX; [ -x "$(command -v COMMANDNAME)"]будет работать в двух других. Похоже, что об этой ошибке уже сообщалось, но она еще не получила никаких ответов: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h

210

Я согласен с 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. Смотрите здесь для его спецификации: команда - выполнить простую команду

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


3
То же, что и выше - exit 1;убивает xterm, если вызывается оттуда.
пользователь неизвестен

1
Это не будет работать со стандартным sh: вы &> не действительны инструкции по перенаправлению.
января

7
@jyavenard: Вопрос помечен как bash , отсюда и более лаконичная нотация перенаправления, относящаяся к bash &>/dev/null. Тем не менее, я согласен с вами, что действительно важно, это переносимость, я соответственно отредактировал свой ответ, теперь используя стандартный sh redirect >/dev/null 2>&1.
GregV

чтобы еще больше улучшить этот ответ, я бы сделал две вещи: 1: используйте «&>», чтобы упростить его, как ответ Джоша. 2: разбить {} на дополнительную строку, поместив перед эхом вкладку, для удобства чтения
knocte

Я просто поставить этот один вкладыш в функцию Баша , если кто -то хочет его ... github.com/equant/my_bash_tools/blob/master/tarp.bash
EQUANT

94

У меня есть функция, определенная в моем .bashrc, которая делает это проще.

command_exists () {
    type "$1" &> /dev/null ;
}

Вот пример того, как это используется (из моего .bash_profile.)

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi

Что делает &>?
Саад Малик


&>может быть недоступно в вашей версии Bash. Код Марчелло должен работать нормально; это делает то же самое.
Джош Стратер

3
Не работает со встроенными и зарезервированными словами: попробуйте это, например, со словом then. Посмотрите этот ответ, если вам требуется, чтобы исполняемый файл существовал в $PATH.
Том Хейл

84

Это зависит от того, хотите ли вы узнать, существует ли он в одном из каталогов в $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программы.


22
Вы действительно не должны использовать «который» по причинам, изложенным в моем комментарии.
лунат

39

Расширяя ответы @ lhunath и @ GregV, вот код для людей, которые хотят легко вставить эту проверку в ifутверждение:

exists()
{
  command -v "$1" >/dev/null 2>&1
}

Вот как это использовать:

if exists bash; then
  echo 'Bash exists!'
else
  echo 'Your system does not have Bash'
fi

13
Готовность учиться и совершенствоваться должны быть вознаграждены. +1 Это чисто и просто. Единственное, что я могу добавить, это то, что это commandудается даже для псевдонимов, что может быть несколько нелогично. Проверка существования в интерактивной оболочке даст другие результаты, чем когда вы перемещаете ее в скрипт.
Палек

1
Я только что проверил и использую shopt -u expand_aliasesигнорирующие / скрывающие псевдонимы (как alias ls='ls -F'упомянуто в другом ответе) и shopt -s expand_aliasesразрешаю их через command -v. Так что, возможно, его следует установить до проверки и отменить после, хотя это может повлиять на возвращаемое значение функции, если вы не захватите и не вернете выходные данные вызова команды в явном виде.
dragon788

24

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

test -x filename

или

[ -x filename ]

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

 -x file
          True if file exists and is executable.

26
Это означает, что вам уже нужно знать полный путь к приложению.
лунат

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

16

Чтобы использовать hash, как предполагает @lhunath , в скрипте Bash:

hash foo &> /dev/null
if [ $? -eq 1 ]; then
    echo >&2 "foo not found."
fi

Этот скрипт запускается, hashа затем проверяет $?, равен ли код завершения самой последней команды, в которой хранится значение 1. Если hashне найдет foo, код выхода будет 1. Если fooприсутствует, код выхода будет 0.

&> /dev/nullперенаправляет стандартные ошибки и стандартный вывод из hashтак , что он не появляется на экране и echo >&2записывает сообщение в стандартный поток ошибок.


8
Почему не просто if hash foo &> /dev/null; then ...?
Бени Чернявский-Паскин

9

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

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi

3
Скобки не являются частью ifсинтаксиса, просто используйте if builtin type -p vim; then .... И обратные ссылки - действительно древний и устаревший синтаксис, $()поддерживаемый даже shво всех современных системах.
nyuszika7h

9

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

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?

Проверьте, установлены ли некоторые aptпакеты, dpkg -sи установите их иначе .

См. Проверьте, установлен ли пакет apt-get, а затем установите его, если он не в Linux.

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


1
Недословный способ сделать это: 1) избавиться от спецификатора ширины; 2) добавить пробел после имени вашей команды printf; 3) направить ваш цикл for column -t(часть util-linux).
Патрис Левеск

8

Если вы проверите наличие программы, вы, вероятно, все равно будете запускать ее позже. Почему бы не попробовать запустить его в первую очередь?

if foo --version >/dev/null 2>&1; then
    echo Found
else
    echo Not found
fi

Это более надежная проверка запуска программы, чем просто просмотр каталогов PATH и прав доступа к файлам.

Кроме того, вы можете получить полезный результат от вашей программы, например, ее версию.

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


6

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

type -p foo: он работает с Z shell, Bash и ash ( BusyBox ), но не с Dash (это интерпретируется -pкак аргумент).

command -v foo: работает с Z shell, Bash, Dash, но не с пеплом (BusyBox) ( -ash: command: not found).

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


4

Используйте встроенные команды Bash, если можете:

which programname

...

type -P programname

15
А? whichэто не встроенный Bash.
tripleee

Тип -P имя программы должно быть предпочтительным, см. принятый ответ
RobertG

@RobertG Я вижу только то, что -Pэто не POSIX. Почему type -Pпредпочтительнее?
mikemaccana

Я должен был сформулировать это как «быть предпочтительным в среде bash» - так как я намеревался ответить на предыдущий комментарий, относящийся к bash. Во всяком случае, это было много лет назад - я полагаю, я должен просто снова указать вам ответ, помеченный как «принятый»
RobertG

4

Команда -vработает нормально, если для параметра установлен параметр POSIX_BUILTINS<command> , но сбой. (Он работал у меня годами, но недавно я столкнулся с тем, где он не работал.)

Я считаю следующее более надежным:

test -x $(which <command>)

Поскольку он проверяет три вещи: путь, существование и разрешение на выполнение.


Не работает test -x $(which ls)возвращает 0, как это делает test -x $(which sudo), даже если lsустановлен и работоспособный и sudoдаже не установлен в Докер контейнера я бег в.
водорослевом

@algal Вы должны использовать кавычки, я думаю, такtest -x "$(which <command>)"
JoniVR

@algal Может быть, lsэто псевдоним? Я не думаю, что это будет работать, если команда имеет параметр.
AnthonyC

3

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

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

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

Как видно из вышесказанного, ответ «0» на запрос означает, что пакет не установлен. Это функция «grep» - «0» означает, что совпадение найдено, «1» означает, что совпадение не найдено.


10
Тем не менее, анти-шаблон cmd; if [ $? -eq 0 ]; thenдолжен быть рефакторинг вif cmd; then
tripleee

Это работает только для библиотек, установленных через dpkgилиapt
Weijun Zhou

3

Здесь есть тонна вариантов, но я не удивился, что быстрых однострочников. Вот что я использовал в начале своих сценариев:

[[ "$(command -v mvn)" ]] || { echo "mvn is not installed" 1>&2 ; exit 1; }
[[ "$(command -v java)" ]] || { echo "java is not installed" 1>&2 ; exit 1; }

Это основано на выбранном ответе здесь и другом источнике.


2

Я бы сказал, что нет никакого портативного и 100% надежного способа из-за болтающихся aliasэс. Например:

alias john='ls --color'
alias paul='george -F'
alias george='ls -h'
alias ringo=/

Конечно, проблематично только последнее (без обид на Ринго!). Но все они действительны aliasс точки зрения command -v.

Чтобы отвергнуть висячие сообщения, такие как ringo, мы должны проанализировать выходные данные встроенной aliasкоманды оболочки и вернуться к ним ( command -vздесь не лучше alias). Для этого нет никакого переносимого решения, и даже Bash- конкретное решение довольно утомительно.

Обратите внимание, что подобное решение безоговорочно отклонит alias ls='ls -F':

test() { command -v $1 | grep -qv alias }

Хорошая точка зрения. Однако при запуске из скрипта bash псевдонимы не видны.
Василий Муса

1
Также есть проблема, она вернет false, когда команда 'alias' проверена. Когда он должен вернуть истину. Пример: тест "псевдоним"
Василий Муса

2
Я только что проверил и использую shopt -u expand_aliasesигнорирует / скрывает эти псевдонимы и shopt -s expand_aliasesпоказывает их через command -v.
dragon788

2

Это скажет в зависимости от местоположения, если программа существует или нет:

    if [ -x /usr/bin/yum ]; then
        echo "This is Centos"
    fi

Да, я добавил эту команду, если вам нужно установить пакет в sevrer, Open suse, centos, Debian
Klevin Kona

Подсветка синтаксиса отключена в строке "echo". Каково решение? Это предполагает, что сценарий Bash должен быть другим?
Питер Мортенсен

@PeterMortensen Подсветка синтаксиса отключена, потому что она не распознает, что это строка.
Адриен

1

Команда 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 executable

       2      if an invalid option is specified

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


Используйте который, если вы ищете любой исполняемый файл с именем foo, но посмотрите мой ответ, если вы хотите проверить определенный файл / путь / к / a / named / foo. Также обратите внимание на то, что может быть недоступно на некоторых минимальных системах, хотя оно должно присутствовать на любой полноценной установке ...
dmckee --- ex-moderator kitten

9
Не полагайтесь на статус выхода которого. Многие операционные системы имеют функцию, которая даже не устанавливает состояние выхода, кроме 0.
lhunath

1

Моя установка для Debian сервера :

У меня была проблема, когда несколько пакетов содержали одно и то же имя.

Например apache2. Так что это было мое решение:

function _apt_install() {
    apt-get install -y $1 > /dev/null
}

function _apt_install_norecommends() {
    apt-get install -y --no-install-recommends $1 > /dev/null
}
function _apt_available() {
    if [ `apt-cache search $1 | grep -o "$1" | uniq | wc -l` = "1" ]; then
        echo "Package is available : $1"
        PACKAGE_INSTALL="1"
    else
        echo "Package $1 is NOT available for install"
        echo  "We can not continue without this package..."
        echo  "Exitting now.."
        exit 0
    fi
}
function _package_install {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install $1
            sleep 0.5
        fi
    fi
}

function _package_install_no_recommends {
    _apt_available $1
    if [ "${PACKAGE_INSTALL}" = "1" ]; then
        if [ "$(dpkg-query -l $1 | tail -n1 | cut -c1-2)" = "ii" ]; then
             echo  "package is already_installed: $1"
        else
            echo  "installing package : $1, please wait.."
            _apt_install_norecommends $1
            sleep 0.5
        fi
    fi
}

1

Если вы, ребята / девочки, не можете получить ответы на вопросы, приведенные здесь в ответах, и вырываете волосы из спины, попробуйте выполнить ту же команду, используя 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

Различия вызваны разницей между интерактивным и неинтерактивным режимами оболочки. Ваш ~ / .bashrc доступен только для чтения, когда оболочка не авторизована и интерактивна. Второй выглядит странно, потому что это должно быть вызвано разницей в переменной окружения PATH, но подоболочки наследуют среду.
Палек

В моем случае .bashrcесть [ -z "$PS1" ] && returnпредваряющий, # If not running interactively, don't do anythingпоэтому я думаю, что это причина, по которой даже явный источник bashrc в неинтерактивном режиме не помогает. Проблема может быть workarounded путем вызова сценария с ss64.com/bash/source.html оператора точка , . ./script.shно это не вещь , один хотел бы помнить , набирать каждый раз.
user619271

1
Сценарии поиска, которые не должны быть получены, - плохая идея. Все, что я пытался сказать, - это то, что ваш ответ имеет мало общего с задаваемым вопросом и имеет много общего с Bash и его (не) интерактивным режимом.
Палек

Если бы он объяснил, что происходит в этих случаях, это было бы полезным дополнением к ответу.
Палек

0

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

one_folder/process

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

hash one_folder/process; echo $? # will always output '0'

4
«Для этого родительская папка one_folder должна быть в $PATH» - это совершенно неточно. Попробуй это. Чтобы это работало, one_folder должен быть в текущем каталоге .
Wildcard

0

Я второй использование "команда -v". Например, вот так:

md=$(command -v mkdirhier) ; alias md=${md:=mkdir}  # bash

emacs="$(command -v emacs) -nw" || emacs=nano
alias e=$emacs
[[ -z $(command -v jed) ]] && alias jed=$emacs

0

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

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

3
Условие довольно бесполезно, по модулю время запуска для запуска apt-get, так как apt-get будет удовлетворен и завершится, если git-core уже установлен.
Трипли

3
Время его запуска не является ничтожным, но более важной мотивацией является sudo: без условия он всегда останавливается и запрашивает пароль (если вы недавно не сделали sudo). Кстати, это может быть полезно, sudo -p "Type your password to install missing git-core: "чтобы подсказка не появлялась на ровном месте.
Бени Чернявский-Паскин

0

Чтобы имитировать Bash type -P cmd, мы можем использовать POSIX-совместимый env -i type cmd 1>/dev/null 2>&1.

man env
# "The option '-i' causes env to completely ignore the environment it inherits."
# In other words, there are no aliases or functions to be looked up by the type command.

ls() { echo 'Hello, world!'; }

ls
type ls
env -i type ls

cmd=ls
cmd=lsx
env -i type $cmd 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }

7
Почему за это проголосовали? В каких системах это на самом деле работает для вас? typeКажется, что builtinв большинстве оболочек, это не может работать, потому что envиспользует execvpдля запуска, commandпоэтому commandне может быть builtinbuiltinвсегда будет выполняться в той же среде). Это не может для меня bash, ksh93, zsh, busybox [a]shи dashвсе , которые обеспечивают typeкак встроенная команда.
Адриан Фрювирт

0

Если нет 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 (Snow Leopard) использование Bash 4.2.24 (2) command -v lsне соответствует перемещению /bin/ls-temp.


0

В случае , если вы хотите проверить , если программа существует , и это действительно программа, не Bash встроенной командой , то command, typeиhash не подходит для тестирования , как они все возвращения 0 статуса выхода для встроенных команд.

Например, есть время программа , которая предоставляет больше возможностей , чем время встроенного команды. Чтобы проверить, существует ли программа, я бы предложил использовать whichкак в следующем примере:

# First check if the time program exists
timeProg=`which time`
if [ "$timeProg" = "" ]
then
  echo "The time program does not exist on this system."
  exit 1
fi

# Invoke the time program
$timeProg --quiet -o result.txt -f "%S %U + p" du -sk ~
echo "Total CPU time: `dc -f result.txt` seconds"
rm result.txt

0

Я хотел получить ответ на тот же вопрос, но запустить его в Makefile.

install:
    @if [[ ! -x "$(shell command -v ghead)" ]]; then \
        echo 'ghead does not exist. Please install it.'; \
        exit -1; \
    fi

-1

скрипт

#!/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.

-1

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.