Как проверить, действительно ли команда действительна в сценарии bash? [Дубликат]

Возможное переносное решение - написать распределитель самостоятельно. Вам не нужно использовать стек процесса, просто имитируйте его в куче. Выделите большой объем памяти в начале и напишите над ним распределитель стека, чтобы использовать его при распределении. Google «Требования к подписчикам» для получения информации о том, как его достичь на C ++.

Я не уверен, что термин «Stack Allocator» является каноническим, но я имею в виду, что вы должны ставить стеки как ограничения на то, где должно происходить распределение или освобождение. Поскольку вы сказали, что ваш алгоритм подходит для этого шаблона, я думаю, что это будет легко.

1660
задан Ciro Santilli 新疆改造中心 六四事件 法轮功 5 June 2018 в 07:24
поделиться

31 ответ

Ответ

Совместимость с 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
}
2295
ответ дан Cory Klein 16 August 2018 в 05:15
поделиться
  • 1
    @Geert: часть & amp; gt; / dev / null скрывает сообщение 'type', когда 'foo' не существует. & Gt; & amp; 2 на эхо-сигнале обязательно отправит сообщение об ошибке в стандартную ошибку вместо стандартного вывода; потому что это соглашение. Оба они отображаются на вашем терминале, но стандартная ошибка, безусловно, является предпочтительным выходом для сообщений об ошибках и неожиданными предупреждениями. – lhunath 19 July 2010 в 14:43
  • 2
    флаг -P не работает в 'sh', например stackoverflow.com/questions/2608688/… – momeara 1 April 2011 в 20:18
  • 3
    Для тех, кто не знаком с передовым переходом i / o в bash: 1) 2>&- («дескриптор дескриптора выходного файла 2», который является stderr) имеет тот же результат, что и 2> /dev/null; 2) >&2 является ярлыком для 1>&2, который вы можете распознать как «перенаправление stdout на stderr». Дополнительную информацию см. На странице перенаправления ввода / вывода URL-адреса Advanced Bash Scripting Guide . – mikewaters 21 December 2011 в 21:48
  • 4
    Это решение не работает с FreeBSD / sh. хэш на FreeBSD всегда возвращается с кодом 0 – jyavenard 4 March 2012 в 06:44
  • 5
  • 6
    @mikewaters 2>&- является не так же, как 2>/dev/null. Первый закрывает файловый дескриптор, а последний просто перенаправляет его на /dev/null. Возможно, вы не видите ошибку, потому что программа пытается сообщить вам о stderr, что stderr закрыт. – nyuszika7h 5 November 2014 в 15:36

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

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

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

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

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

7
ответ дан 0xF 16 August 2018 в 05:15
поделиться
  • 1
    Это подход, который я использую, чтобы проверить, установлен ли git. Это очень быстро. Верно, что не все команды делают это быстро, и не все имеют этот флаг; хорошо для того, чтобы упомянуть об этом. – Wildcard 1 January 2016 в 03:53

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

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

Он использует shell builtin и статус программного эха для stdout и ничего для stderr другой рукой если команда не найдена, она имеет статус echos только для stderr.

0
ответ дан A.N 16 August 2018 в 05:15
поделиться

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

Он возвращает 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

2
ответ дан Adam Davis 16 August 2018 в 05:15
поделиться
  • 1
    Используйте это, если вы ищете исполняемый файл с именем foo, но посмотрите мой ответ, если вы хотите проверить конкретный файл / путь / в / a / named / foo. Также обратите внимание, что это может быть недоступно в некоторых минимальных системах, хотя оно должно присутствовать на любой полноценной установке ... – dmckee 26 February 2009 в 23:01
  • 2
    Не полагайтесь на статус выхода. У многих операционных систем есть то, что даже не устанавливает статус выхода, отличный от 0. – lhunath 24 March 2009 в 13:46
checkexists() {
    while [ -n "$1" ]; do
        [ -n "$(which "$1")" ] || echo "$1": command not found
        shift
    done
}
0
ответ дан Anonymous 16 August 2018 в 05:15
поделиться
  • 1
    Код полезен, но слова действительно многого при публикации после многих других ответов, попробуйте его когда-нибудь :) – Nikana Reklawyks 27 October 2012 в 01:56
Команда

-v работает нормально, если для параметра <command> установлено значение параметра POSIX_BUILTINS, но может быть неудачно, если нет. (он работал для меня в течение многих лет, но в последнее время столкнулся с тем, где он не работал).

Я считаю следующее более отказоустойчивым:

test -x $(which <command>)

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

0
ответ дан AnthonyC 16 August 2018 в 05:15
поделиться

Вариант hash имеет одну ошибку: в командной строке вы можете, например, ввести

one_folder/process

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

hash one_folder/process; echo $? # will always output '0'
1
ответ дан anycast.cw 16 August 2018 в 05:15
поделиться
  • 1
    «Для этого родительская папка одной_папки должна находиться в $PATH». Это полностью неточно. Попробуй. Чтобы это сработало, one_folder должен находиться в текущем каталоге . – Wildcard 1 January 2016 в 03:55

hash foo 2>/dev/null: работает с zsh, bash, тире и золой.

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

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

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

4
ответ дан blueyed 16 August 2018 в 05:15
поделиться

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

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

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

latex     OK
pandoc    missing

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

5
ответ дан Ciro Santilli 新疆改造中心 六四事件 法轮功 16 August 2018 в 05:15
поделиться
  • 1
    Неверный способ сделать это: 1) избавиться от спецификатора ширины; 2) добавьте пробел после имени вашей команды printf; 3) подключите цикл for к column -t (часть util-linux). – Patrice Levesque 22 February 2015 в 19:15

Если внешняя 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.

16
ответ дан Community 16 August 2018 в 05:15
поделиться

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

66
ответ дан dreamlax 16 August 2018 в 05:15
поделиться
  • 1
    Вы действительно не должны использовать & quot ;, & quot; по причинам, изложенным в моем комментарии. – lhunath 24 March 2009 в 15:53

Сценарий

#!/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 August 2018 в 05:15
поделиться

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

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

#!/bin/bash
set -e
git --version >> /dev/null
0
ответ дан fjk 16 August 2018 в 05:15
поделиться

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

test -x filename

или

[ -x filename ]

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

 -x file
          True if file exists and is executable.
19
ответ дан Hengjie 16 August 2018 в 05:15
поделиться
  • 1
    Это означает, что вам нужно уже знать полный путь к приложению. – lhunath 24 March 2009 в 13:45
  • 2
    ОП не указал, хочет ли он проверить конкретный экземпляр или какой-либо исполняемый экземпляр ... Я ответил так, как я его прочитал. – dmckee 24 March 2009 в 17:42

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

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

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

if command_exists mvim ; then
    export VISUAL="mvim --nofork"
fi
81
ответ дан Josh Strater 16 August 2018 в 05:15
поделиться

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

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

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

0
ответ дан keisar 16 August 2018 в 05:15
поделиться

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

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

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

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

4
ответ дан Nathan Crause 16 August 2018 в 05:15
поделиться
  • 1
    Согласовано. Это лучшее решение здесь, поскольку оно работает как с библиотеками, так и с программами. – mlissner 12 July 2010 в 22:42
  • 2
    Однако анти-шаблон cmd; if [ $? -eq 0 ]; then должен быть реорганизован на if cmd; then – tripleee 21 October 2013 в 08:04

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

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

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

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

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

test() { command -v $1 | grep -qv alias }
2
ответ дан nodakai 16 August 2018 в 05:15
поделиться
  • 1
    Хорошая точка зрения. Однако при запуске из сценария bash псевдонимы не видны. – Basil Musa 23 March 2016 в 17:08
  • 2
    Там также проблема, она вернет false, когда проверяется команда 'alias'. Когда он должен вернуть true. Пример: тестовый псевдоним & quot; – Basil Musa 23 March 2016 в 17:12
  • 3
    Я просто тестировал и использовал shopt -u expand_aliases игнорирует / скрывает эти псевдонимы, а shopt -s expand_aliases показывает их через command -v. – dragon788 2 July 2017 в 03:07

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

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

Пример:

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

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

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

Кроме того, это не удастся, если команда, которую вы ищете, была определена как псевдоним.

242
ответ дан nyuszika7h 16 August 2018 в 05:15
поделиться
  • 1
    Мне нравится этот ответ, потому что тест прост в использовании в скрипте. Это не требует создания функции. – Stephen Ostermiller 14 February 2017 в 01:00
  • 2
    Будет ли command -v создавать путь даже для неисполняемого файла? То есть, -x действительно необходимо? – einpoklum 26 October 2017 в 10:14
  • 3
    @einpoklum -x проверяет, что файл является исполняемым, и это вопрос. – Ken Sharp 26 October 2017 в 13:03
  • 4
    @KenSharp: Но это кажется излишним, поскольку command сам будет проверять его исполняемость - не так ли? – einpoklum 26 October 2017 в 13:04
  • 5
    @einpoklum Да, это необходимо. На самом деле даже это решение может сломаться в одном краевом случае. Спасибо, что привлек это к моему вниманию. dash, bash и zsh все пропускают неиспользуемые файлы в $PATH при выполнении команды. Однако поведение command -v очень противоречиво. В тире он возвращает первый соответствующий файл в $PATH, независимо от того, является ли он исполняемым или нет. В bash он возвращает первое исполняемое совпадение в $PATH, но если его нет, он может вернуть неисполняемый файл. И в zsh он никогда не вернет неисполняемый файл. – nyuszika7h 26 October 2017 в 13:52
  • 6
    – nyuszika7h 26 October 2017 в 14:12

Развернувшись на ответах @ 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
27
ответ дан Romário 16 August 2018 в 05:15
поделиться
  • 1
    Почти такой же неуклюжий, как может быть. Читайте о статусе выхода в man bash и узнайте, как его использовать. Это сделает ваш код намного проще и элегантнее. Скобки не являются частью синтаксиса if, они являются лишь сокращением для команды test. if проверяет, выполнена ли команда (имеет статус выхода 0). – Palec 8 December 2015 в 09:09
  • 2
    @Palec: Ты прав, он был довольно неуклюжим. Я немного почистил его, и я надеюсь, что теперь он выглядит более уместным. – Romário 11 December 2015 в 21:44
  • 3
    Готовность учиться и совершенствоваться должна быть вознаграждена. +1 Это чисто и просто. Единственное, что я могу добавить, это то, что command преуспевает даже для псевдонимов, что может быть несколько противоречивым. Проверка наличия в интерактивной оболочке даст разные результаты, когда вы переместите ее в скрипт. – Palec 12 December 2015 в 10:23
  • 4
    Я просто тестировал и использовал shopt -u expand_aliases игнорирует псевдонимы (например, alias ls='ls -F', упомянутые в другом ответе), а shopt -s expand_aliases разрешает их через command -v. Поэтому, возможно, он должен быть установлен перед проверкой и отменен после, хотя это может повлиять на возвращаемое значение функции, если вы не запишете и не возвращаете вывод вызова команды явно. – dragon788 2 July 2017 в 03:13

Если вы хотите проверить, существует ли программа и действительно ли это программа, а не встроенная команда 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
1
ответ дан rpr 16 August 2018 в 05:15
поделиться

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

which programname

...

type -P programname
7
ответ дан Steven Penny 16 August 2018 в 05:15
поделиться
  • 1
    А? which не является встроенным Bash. – tripleee 21 October 2013 в 08:01
  • 2
    тип -P имя_программы должно быть предпочтительным, см. принятый ответ – RobertG 25 July 2016 в 16:30
  • 3
    Скобки не являются частью синтаксиса if, просто используйте if builtin type -p vim; then .... И обратные ссылки - действительно древний и устаревший синтаксис, $() поддерживается даже sh во всех современных системах. – nyuszika7h 2 February 2017 в 15:42
  • 4
    @RobertG Все, что я вижу, это -P не POSIX. Почему type -P предпочтительнее? – mikemaccana 2 January 2018 в 19:24
  • 5
    Я должен был сформулировать, что «предпочтительнее в средах bash». - поскольку я намерен ответить на предыдущий комментарий, основанный на bash. Так или иначе, это было много лет назад - я думаю, я должен просто снова указать на ответ, обозначенный как «accpeted». – RobertG 5 January 2018 в 11:06

моя настройка для сервера 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
ответ дан ThCTLo 16 August 2018 в 05:15
поделиться

Чтобы подражать 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; }
1
ответ дан tim 16 August 2018 в 05:15
поделиться
  • 1
    Почему это поддерживается? На каких системах это действительно работает для вас? type кажется builtin в большинстве оболочек, поэтому это не может работать, потому что env использует execvp для запуска command, поэтому command не может быть builtinbuiltin всегда будет работать в одной среде). Это не удается для меня в bash, ksh93, zsh, busybox [a]sh и dash, все из которых обеспечивают type как встроенную оболочку. – Adrian Frühwirth 17 April 2014 в 10:00

Во-вторых, использование команды -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
1
ответ дан user2961933 16 August 2018 в 05:15
поделиться

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

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

$ 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 August 2018 в 05:15
поделиться
  • 1
    Различия обусловлены различием между интерактивным и неинтерактивным режимами оболочки. Ваш ~ / .bashrc читается только тогда, когда оболочка не является логиной и интерактивной. Второй выглядит странно, потому что это должно быть вызвано различием в переменной среды PATH, но подоболочки наследуют среду. – Palec 26 August 2015 в 10:47
  • 2
    В моем случае .bashrc имеют [ -z "$PS1" ] && return, добавленные # If not running interactively, don't do anything, поэтому я предполагаю, что это является причиной того, что даже явный источник bashrc в неинтерактивном режиме не помогает. Проблема может быть решена путем вызова сценария с помощью оператора ss64.com/bash/source.html dot . ./script.sh, но это не то, что хотелось бы запомнить каждый раз. – user619271 26 August 2015 в 12:16
  • 3
    Сценарии источников, которые не должны использоваться, - плохая идея. Все, что я пытался сказать, это то, что ваш ответ имеет мало общего с вопросом, который задают, и что делать с Bash и его (не) интерактивным режимом. – Palec 26 August 2015 в 13:12
  • 4
    Мой ответ может помочь некоторым потерянным душам не потерять рассудок, когда они сталкиваются с одной и той же проблемой, пытаясь понять, почему проверка подлинности программы не проходит без видимых причин. – user619271 26 August 2015 в 15:07
  • 5
    Если он объяснит, что происходит в этих случаях, это будет полезным дополнением к ответу. – Palec 26 August 2015 в 16:06

Я согласен с 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 - нет.

190
ответ дан Veger 16 August 2018 в 05:15
поделиться
  • 1
    То же, что и выше - exit 1; убивает xterm, если вызвано оттуда. – user unknown 18 February 2012 в 19:14
  • 2
    Это не будет работать на стандартном sh: you & amp; & gt; не является действительной инструкцией перенаправления. – jyavenard 4 March 2012 в 13:19
  • 3
    @jyavenard: вопрос помечен тегом bash , следовательно, более кратким обозначением перенаправления, специфичным для bash &>/dev/null. Тем не менее, я согласен с вами, что действительно важно - переносимость, я отредактировал свой ответ соответственно, теперь используя стандартный sh redirect >/dev/null 2>&1. – GregV 5 March 2012 в 12:58
  • 4
    чтобы еще больше улучшить этот ответ, я бы сделал две вещи: 1: use & quot; & amp; & gt; & quot; чтобы упростить его, как ответ Джоша. 2: сломать {} в дополнительную строку, поместив вкладку перед эхом, для удобства чтения – knocte 21 May 2016 в 13:06
  • 5
    Я просто помещал этот один вкладыш в функцию bash, если кто-то этого захочет ... github.com/equant/my_bash_tools/blob/master/tarp.bash – equant 29 September 2017 в 19:26

Я использую очень удобную и короткую версию:

dpkg -s curl 2>/dev/null >/dev/null || apt-get -y install curl

Так просто, если нужно проверить только одну программу.

0
ответ дан Xynox 16 August 2018 в 05:15
поделиться

Чтобы использовать 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 записывает сообщение к стандартной ошибке.

16
ответ дан Community 16 August 2018 в 05:15
поделиться

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

if [ `builtin type -p vim` ]; then echo "TRUE"; else echo "FALSE"; fi
7
ответ дан Steven Penny 16 August 2018 в 05:15
поделиться
  • 1
    Скобки не являются частью синтаксиса if, просто используйте if builtin type -p vim; then .... И обратные ссылки - действительно древний и устаревший синтаксис, $() поддерживается даже sh во всех современных системах. – nyuszika7h 2 February 2017 в 15:42
Другие вопросы по тегам:

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