Como posso verificar se existe um programa a partir de um script Bash?


2211

Como eu validaria a existência de um programa, de uma maneira que retorne um erro e saia, ou continue com o script?

Parece que deveria ser fácil, mas está me deixando perplexo.


O que é um "programa"? Inclui funções e aliases? whichretorna verdadeiro para estes. typesem argumentos também retornará true para palavras reservadas e embutidos no shell. Se "programa" significa "permutável em $PATH", consulte esta resposta .
Tom Hale

Respostas:


3055

Responda

Compatível com POSIX:

command -v <the_command>

Para ambientes específicos do Bash:

hash <the_command> # For regular commands. Or...
type <the_command> # To check built-ins and keywords

Explicação

Evite which. Não só é um processo externo você está lançando para fazer muito pouco (ou seja, builtins gosto hash, typeou commandestão muito mais barato), você também pode contar com os builtins para realmente fazer o que quiser, enquanto os efeitos dos comandos externos podem facilmente variar de sistema para sistema.

Por que se importar?

  • Muitos sistemas operacionais possuem um statuswhich que nem define um status de saída , o que significa que if which fooele nem funciona lá e sempre informa que fooexiste, mesmo que não exista (observe que alguns shells POSIX parecem fazer isso hashtambém).
  • Muitos sistemas operacionais fazem whichcoisas personalizadas e más, como alterar a saída ou até se conectar ao gerenciador de pacotes.

Então, não use which. Em vez disso, use um destes:

$ 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; }

(Nota secundária secundária: alguns sugerem que 2>&-é o mesmo, 2>/dev/nullmas mais curto - isso é falso . 2>&-Fecha o FD 2, que causa um erro no programa ao tentar gravar no stderr, que é muito diferente de gravar com sucesso e descartar a saída (e perigoso!))

Se o seu hash bang for /bin/sh, você deve se preocupar com o que o POSIX diz. typee hash's códigos de saída não são terrivelmente bem definido pela POSIX, e hashé visto para sair com êxito quando o comando não existe (não vi isso com typeainda). commandO status de saída é bem definido pelo POSIX, de modo que provavelmente é o mais seguro de usar.

Se o seu script usar bash, as regras do POSIX não importam mais e as duas typee hashse tornam perfeitamente seguras. typeagora tem -Pque procurar apenas PATHoehash tem o efeito colateral que a localização do comando será hash (para mais rápido lookup próxima vez que você usá-lo), que normalmente é uma coisa boa, pois você provavelmente verificar a sua existência, a fim de realmente usá-lo .

Como um exemplo simples, aqui está uma função que é executada gdatese existir, caso contrário date:

gnudate() {
    if hash gdate 2>/dev/null; then
        gdate "$@"
    else
        date "$@"
    fi
}

35
@ Geert: A parte &> / dev / null oculta a mensagem 'type' emitida quando 'foo' não existe. O> & 2 no eco certifica-se de enviar a mensagem de erro ao erro padrão em vez da saída padrão; porque isso é convenção. Ambos aparecem no seu terminal, mas o erro padrão é definitivamente a saída preferida para mensagens de erro e avisos inesperados.
Lhunath 19/07

5
a bandeira -P não funciona em 'sh', por exemplo stackoverflow.com/questions/2608688/...
momeara

130
Para aqueles que não estão familiarizados com o redirecionamento de E / S 'avançado' no bash: 1) 2>&- ("fechar o descritor de arquivo de saída 2", que é stderr) tem o mesmo resultado que 2> /dev/null; 2) >&2é um atalho para o 1>&2qual você pode reconhecer como "redirecionar stdout para stderr". Consulte a página de redirecionamento de E / S do Advanced Bash Scripting Guide para obter mais informações.
Mikewaters

9
@mikewaters O ABS parece bastante avançado e descreve uma ampla variedade de funcionalidades de CLI bash e não bash, mas é muito negligente em muitos aspectos e não segue as boas práticas. Não tenho espaço suficiente neste comentário para fazer uma redação; mas eu pode colar alguns exemplos aleatórios de código BAD: while read element ; do .. done <<< $(echo ${ArrayVar[*]}), for word in $(fgrep -l $ORIGINAL *.txt), ls -l "$directory" | sed 1d , {{para uma em seq $BEGIN $END}}, ... Muitos têm tentado entrar em contato com os autores e propor melhorias, mas não é nenhuma wiki e solicitações de ter desembarcado em ouvidos surdos.
Lhunath

56
@mikewaters não2>&- é o mesmo que . O primeiro fecha o descritor de arquivo, enquanto o último simplesmente o redireciona para . Você pode não ver um erro porque o programa tenta informá-lo no stderr que o stderr está fechado. 2>/dev/null/dev/null
precisa saber é o seguinte

577

A seguir, é uma maneira portátil de verificar se um comando existe $PATH e é executável:

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

Exemplo:

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

A verificação do executável é necessária porque o bash retorna um arquivo não executável se nenhum arquivo executável com esse nome for encontrado $PATH.

Observe também que, se um arquivo não executável com o mesmo nome do executável existir anteriormente $PATH, o dash retornará o anterior, mesmo que o último fosse executado. Este é um erro e viola o padrão POSIX. [ Relatório de erro ] [ Padrão ]

Além disso, isso falhará se o comando que você está procurando tiver sido definido como um alias.


4
Irá command -vproduzir um caminho mesmo para um arquivo não executável? Ou seja, o -x é realmente necessário?
einpoklum

5
O @einpoklum -xtesta se o arquivo é executável, e era essa a pergunta.
Ken afiada

3
@KenSharp: Mas isso parece ser redundante, já que commandele próprio testará se é executável - não é?
einpoklum

13
@einpoklum Sim, é necessário. De fato, mesmo essa solução pode quebrar em um único caso. Obrigado por trazer isso à minha atenção. dash, bash e zsh todos pulam sobre arquivos não executáveis $PATHao executar um comando. No entanto, o comportamento de command -vé muito inconsistente. No traço, ele retorna o primeiro arquivo correspondente $PATH, independentemente de ser executável ou não. No bash, ele retorna a primeira correspondência executável $PATH, mas, se não houver, pode retornar um arquivo não executável. E no zsh, ele nunca retornará um arquivo não executável.
nyuszika7h

5
Até onde eu sei, dashé o único desses três que não é compatível com POSIX; [ -x "$(command -v COMMANDNAME)"]vai funcionar nos outros dois. Parece que este bug já foi relatado, mas não tem todas as respostas ainda: bugs.debian.org/cgi-bin/bugreport.cgi?bug=874264
nyuszika7h

210

Eu concordo com lhunath em desencorajar o uso de which, e sua solução é perfeitamente válida para usuários do Bash . No entanto, para ser mais portátil, command -vdeve ser usado:

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

O comando commandé compatível com POSIX. Veja aqui para sua especificação: command - executa um comando simples

Nota: typeé compatível com POSIX, mas type -Pnão é.


3
O mesmo que acima - exit 1;mata um xterm, se invocado a partir daí.
usuário desconhecido

1
Isso não funcionaria em um sh padrão: você não é uma instrução de redirecionamento válida.
precisa saber é o seguinte

7
@ jyavenard: A pergunta é marcada como bash , daí a notação de redirecionamento mais concisa e específica para o bash &>/dev/null. No entanto, eu concordo com você, o que realmente importa é a portabilidade, editei minha resposta de acordo, agora usando o redirecionamento sh padrão >/dev/null 2>&1.
GregV

para melhorar ainda mais essa resposta, eu faria duas coisas: 1: use "&>" para simplificá-la, como a resposta de Josh. 2: quebrar o {} em uma linha extra, colocando um separador antes do eco, para facilitar a leitura
knocte

Acabei de colocar este um forro em uma função festa se alguém quer ... github.com/equant/my_bash_tools/blob/master/tarp.bash
equant

94

Eu tenho uma função definida no meu .bashrc que facilita isso.

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

Aqui está um exemplo de como é usado (do meu .bash_profile.)

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

O que &>faz?
Saad Malik


&>pode não estar disponível na sua versão do Bash. O código de Marcello deve funcionar bem; faz a mesma coisa.
Josh Strater

3
Falha nas palavras incorporadas e reservadas: tente isso com a palavra then por exemplo. Veja esta resposta se você precisar que o executável exista $PATH.
Tom Hale

84

Depende se você deseja saber se ele existe em um dos diretórios da $PATHvariável ou se você sabe a localização absoluta dele. Se você quiser saber se está na $PATHvariável, use

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

caso contrário, use

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

O redirecionamento para /dev/null/no primeiro exemplo suprime a saída do whichprograma.


22
Você realmente não deve usar "what" pelos motivos descritos em meu comentário.
23410 lhunath

39

Expandindo as respostas de @ lhunath e @ GregV, eis o código para as pessoas que desejam colocar facilmente essa verificação em uma ifdeclaração:

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

Veja como usá-lo:

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

13
A vontade de aprender e melhorar deve ser recompensada. +1 Isso é limpo e simples. A única coisa que posso acrescentar é que é commandbem-sucedida mesmo para pseudônimos, o que pode ser um pouco contra-intuitivo. A verificação da existência em um shell interativo fornecerá resultados diferentes de quando você o move para um script.
Palec 12/12

1
Acabei de testar e usar shopt -u expand_aliasesignora / oculta aliases (como o alias ls='ls -F'mencionado em outra resposta) e os shopt -s expand_aliasesresolvo via command -v. Portanto, talvez ele deva ser definido antes da verificação e desmarcado depois, embora possa afetar o valor de retorno da função se você não capturar e retornar a saída da chamada de comando explicitamente.
precisa saber é o seguinte


16

Para usar hash, como sugere @lhunath , em um script Bash:

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

Esse script é executado hashe verifica se o código de saída do comando mais recente, o valor armazenado em$? , é igual a 1. Se hashnão encontrar foo, o código de saída será 1. Se fooestiver presente, o código de saída será 0.

&> /dev/nullredireciona o erro padrão e a saída padrão dehash modo que ele não aparece na tela eecho >&2 escreve a mensagem para o erro padrão.


8
Por que não apenas if hash foo &> /dev/null; then ...?
Beni Cherniavsky-Paskin

9

Eu nunca recebi as respostas anteriores para trabalhar na caixa a que tenho acesso. Por um lado, typefoi instalado (fazendo o que morefaz). Portanto, a diretiva integrada é necessária. Este comando funciona para mim:

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

3
Os colchetes não fazem parte da ifsintaxe, basta usar if builtin type -p vim; then .... E os backticks são realmente antigos e têm uma sintaxe obsoleta, e $()são suportados mesmo shem todos os sistemas modernos.
precisa saber é o seguinte

9

Verifique várias dependências e informe o status aos usuários finais

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

Saída de amostra:

latex     OK
pandoc    missing

Ajuste o 10para o comprimento máximo do comando. Não é automático, porque não vejo uma maneira POSIX não detalhada de fazê-lo: Como alinhar as colunas de uma tabela separada por espaço no Bash?

Verifique se alguns aptpacotes estão instalados dpkg -se, caso contrário, instale-os .

Consulte: Verifique se um pacote apt-get está instalado e instale-o se não estiver no Linux

Foi mencionado anteriormente em: Como posso verificar se existe um programa a partir de um script Bash?


1
Maneira não-detalhada de fazer isso: 1) livrar-se do especificador de largura; 2) adicione um espaço após o nome do seu comando printf; 3) canalize seu loop for para column -t(parte do util-linux).
Patrice Levesque 22/02

8

Se você verificar a existência do programa, provavelmente o executará mais tarde. Por que não tentar executá-lo em primeiro lugar?

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

É uma verificação mais confiável que o programa é executado do que apenas olhar para diretórios PATH e permissões de arquivo.

Além disso, você pode obter algum resultado útil do seu programa, como a versão.

Obviamente, os inconvenientes são que alguns programas podem ser pesados ​​para iniciar e outros não têm a --versionopção de sair imediatamente (e com êxito).


6

hash foo 2>/dev/null: funciona com shell Z (Zsh), Bash, Dash e ash .

type -p foo: parece funcionar com o shell Z, Bash e ash ( BusyBox ), mas não o Dash (ele interpreta-p como argumento).

command -v foo: funciona com shell Z, Bash, Dash, mas não ash (BusyBox) (-ash: command: not found ).

Observe também que builtinnão está disponível com ash e Dash.


4

Use os Bash builtins se você puder:

which programname

...

type -P programname

15
Hã? whichnão é um Bash embutido.
Tripleee 21/10

digite programname -P deve ser preferida, ver resposta aceite
RobertG

@RobertG Tudo o que vejo é que -Pnão é POSIX. Por que é type -Ppreferido?
Mikemaccana #

Eu deveria ter formulado que "ser preferido em ambientes do bash" - como pretendia responder ao comentário anterior específico do bash. De qualquer forma, isso foi há anos atrás - acho que devo apenas apontar novamente para a resposta marcada como "aceita"
RobertG

4

O comando -vfunciona bem se a opção POSIX_BUILTINS estiver configurada para o<command> teste, mas poderá falhar se não. (Ele funcionou para mim por anos, mas recentemente encontrei um em que não funcionava.)

Considero o seguinte mais à prova de falhas:

test -x $(which <command>)

Uma vez que ele testa três coisas: permissão de caminho, existência e execução.


Não funciona test -x $(which ls)retorna 0, como o faz test -x $(which sudo), mesmo que lsesteja instalado e executável e sudonem sequer é instalado dentro do recipiente estivador eu estou correndo.
algal

@algal Você precisa usar aspas, eu acho, entãotest -x "$(which <command>)"
JoniVR

@algal Maybe ls seja um alias? Eu não acho que funcionaria se o comando tem parâmetro.
AnthonyC

3

Para os interessados, nenhuma das metodologias das respostas anteriores funciona se você deseja detectar uma biblioteca instalada. Eu imagino que você fique com a verificação física do caminho (potencialmente para arquivos de cabeçalho e outros), ou algo assim (se você estiver em uma distribuição baseada no Debian):

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

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

Como você pode ver acima, uma resposta "0" da consulta significa que o pacote não está instalado. Esta é uma função do "grep" - um "0" significa que uma correspondência foi encontrada, um "1" significa que nenhuma correspondência foi encontrada.


10
No entanto, o anti-padrão cmd; if [ $? -eq 0 ]; thendeve ser reformulado paraif cmd; then
tripleee

Isso funciona apenas para bibliotecas instaladas via dpkgouapt
Weijun Zhou

3

Há uma tonelada de opções aqui, mas fiquei surpreso por não ter falas rápidas. Isto é o que eu usei no início dos meus scripts:

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

Isso se baseia na resposta selecionada aqui e em outra fonte.


2

Eu diria que não existe uma maneira portátil e 100% confiável devido a oscilações aliases. Por exemplo:

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

Obviamente, apenas o último é problemático (sem ofensa a Ringo!). Mas todos eles são válidos aliasdo ponto de vista de command -v.

Para rejeitar outros pendentes ringo, precisamos analisar a saída do aliascomando interno do shell e recursá-los ( command -vnão é superior a aliasaqui.) Não existe uma solução portátil para isso, e até mesmo um Bash- solução específica é bastante entediante.

Observe que uma solução como essa rejeitará incondicionalmente alias ls='ls -F':

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

Bom ponto. No entanto, quando executado a partir de um script bash, os aliases não são visíveis.
Basil Musa

1
Há também um problema, ele retornará false quando o comando 'alias' for verificado. Quando deve retornar verdadeiro. Exemplo: test "alias"
Basil Musa

2
Acabei de testar e usar shopt -u expand_aliasesignora / oculta esses apelidos e os shopt -s expand_aliasesmostra via command -v.
precisa saber é o seguinte

2

Isso informará de acordo com o local se o programa existe ou não:

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

Sim i adicionado este comando se você precisa instalar um pacote no sevrer, Open suse, centos, debian
Klevin Kona

O realce da sintaxe está desativado na linha "eco". Qual é a solução? Isso sugere que o script Bash deve ser diferente?
Peter Mortensen

O realce da sintaxe do @PeterMortensen está desativado porque não reconhece que é uma string.
Adrien

1

O whichcomando pode ser útil. homem que

Retorna 0 se o executável for encontrado e retorna 1 se não for encontrado ou não é executável:

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

O bom whiché que ele descobre se o executável está disponível no ambiente em que whiché executado - ele economiza alguns problemas ...


Use what se estiver procurando por um executável chamado foo, mas veja minha resposta se quiser verificar um arquivo / caminho / para / a / named / foo em particular. Observe também que o que pode não estar disponível em alguns sistemas mínimos, embora deva estar presente em qualquer instalação de pleno direito ...
dmckee --- ex-moderador gatinho

9
Não confie no status de saída. Muitos sistemas operacionais têm uma que que nem sequer definir um status de saída diferente de 0.
lhunath

1

Minha configuração para um servidor Debian :

Eu tive o problema quando vários pacotes continham o mesmo nome.

Por exemplo apache2. Então esta foi a minha solução:

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

Se vocês não conseguem obter as respostas aqui para o trabalho e estão arrancando os cabelos das costas, tente executar o mesmo comando usando bash -c. Basta olhar para esse delírio somnambular. Isto é o que realmente acontece quando você executa $ (subcomando):

Primeiro. Pode fornecer uma saída completamente diferente.

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

Segundo. Pode não fornecer saída alguma.

$ command -v nvm
nvm
$ bash -c "command -v nvm"
$ bash -c "nvm --help"
bash: nvm: command not found

As diferenças são causadas pela diferença entre o modo interativo e não interativo do shell. Seu ~ / .bashrc é somente leitura quando o shell não é de login e é interativo. O segundo parece estranho, porque isso deve ser causado por uma diferença na variável de ambiente PATH, mas os subshells herdam o ambiente.
Palec 26/08/15

No meu caso, .bashrctenho um [ -z "$PS1" ] && returnprefixo, # If not running interactively, don't do anythingentão acho que essa é uma razão pela qual nem o fornecimento explícito de bashrc no modo não interativo não ajuda. O problema pode ser contornado chamando um script com um operador de ponto ss64.com/bash/source.html , . ./script.shmas isso não é algo que você gostaria de lembrar de digitar toda vez.
user619271

1
Scripts de fornecimento que não devem ser adquiridos é uma má ideia. Tudo o que eu estava tentando dizer é que sua resposta tem pouco a ver com a pergunta que está sendo feita e muito a ver com o Bash e seu modo (não) interativo.
Palec 26/08/15

Se explicasse o que está acontecendo nesses casos, seria um adendo útil a uma resposta.
Palec 26/08/15

0

A variante hash tem uma armadilha: na linha de comando, você pode, por exemplo, digitar

one_folder/process

ter processo executado. Para isso, a pasta pai da pasta one_folder deve estar em $ PATH . Mas quando você tenta fazer o hash deste comando, ele sempre será bem-sucedido:

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

4
"Para isso, a pasta pai da pasta one_folder deve estar em $PATH" - isso é completamente impreciso. Tente. Para que isso funcione, a pasta one_folder deve estar no diretório atual .
Curinga

0

Eu segundo o uso do "comando -v". Por exemplo:

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

Eu tive que verificar se o Git foi instalado como parte da implantação do servidor de IC . Meu script final do Bash foi o seguinte (servidor Ubuntu):

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

3
O condicional é bastante inútil, modulo o tempo de inicialização para executar o apt-get, pois o apt-get será satisfeito e sairá se o git-core já estiver instalado.
tripleee

3
Seu tempo de inicialização não é desprezível, mas a motivação mais importante é sudo: sem o condicional, ele sempre parava e solicita a senha (a menos que você tenha feito um sudo recentemente). BTW, pode ser útil fazê- sudo -p "Type your password to install missing git-core: "lo para que o prompt não saia do nada.
Home

0

Para imitar o Bash type -P cmd, podemos usar o compatível com 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
Por que isso está sendo votado? Em quais sistemas isso realmente funciona para você? typeparece ser um builtinna maioria das conchas de modo que este não pode trabalhar porque envusos execvppara executar commandde modo commandnão pode ser um builtin(eo builtinserá sempre executado dentro do mesmo ambiente). Esta falha para mim bash, ksh93, zsh, busybox [a]she dashtodos os quais fornecem typecomo um builtin shell.
Adrian Frühwirth

0

Se não houver nenhum typecomando externo disponível (como concedido aqui ), podemos usar o POSIX compatível 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

Pelo menos no Mac OS X 10.6.8 (Snow Leopard) usando o Bash 4.2.24 (2) command -v lsnão corresponde a um movimento /bin/ls-temp.


0

Caso você queira verificar se um programa existe e é realmente um programa, não um comando interno do Bash , então command, typeehash não são adequados para testar como eles todo o retorno 0 status de saída para built-in comandos.

Por exemplo, existe o programa de horário que oferece mais recursos do que o comando interno de horário . Para verificar se o programa existe, sugiro usar whichcomo no exemplo a seguir:

# 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

Eu queria que a mesma pergunta fosse respondida, mas executada em um Makefile.

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

-1

Roteiro

#!/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"'

Resultado

 [ABRT]: notacmd: command does not exist
hits    command
   0    /usr/bin/bash
Fin.

-1

Eu uso isso, porque é muito fácil:

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

ou

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

Ele usa o status de eco dos programas incorporados e do shell na saída padrão e nada no erro padrão. Por outro lado, se um comando não for encontrado, ele faz eco do status apenas para erro padrão.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.