Como faço para testar se existe um aplicativo em $ PATH?

19

Estou tentando escrever todos os meus shscripts de inicialização / env para trabalhar com o máximo de DRY e o máximo: "funciona em todos os * nix que clono", quanto possível. Isso significa garantir que, se eu tentar executar o código que não existe, o código falhe normalmente. Para esse fim, preciso ser capaz de testar se existem programas. Sei como testar se existe um arquivo, mas não sei como testar para ver se um aplicativo é executável no caminho. Prefiro usar o $ PATH, pois alguns deles precisam trabalhar em arch, ubuntu e centos. Alguns podem estar instalados no meu homedir, em sistemas nos quais não tenho root, outros podem não estar instalados e outros ainda podem estar instalados nos caminhos do sistema.

xenoterracida
fonte
2
Essa resposta SO é a que eu marquei para essas perguntas.
jw013

Respostas:

19

Use type commandname. Isso retorna true se commandnamehouver algo executável: alias, função, comando interno ou externo (consultado $PATH). Como alternativa, use o command commandnameque retorna true se commandnamefor um comando interno ou externo (consultado $PATH).

exists () {
  type "$1" >/dev/null 2>/dev/null
}

Existem algumas variantes sh (definitivamente pré-POSIX; eu conheço o /bin/shOSF1 ≤3.xe algumas versões do shell Almquist encontradas nas versões iniciais do NetBSD e algumas distribuições Linux do século XX), onde typesempre retorna 0 ou não existir. Eu não acho que nenhum sistema enviado com estes neste milênio. Se você os encontrar, aqui está uma função que você pode usar para pesquisar $PATHmanualmente:

exists () { (
    IFS=:
    for d in $PATH; do
      if test -x "$d/$1"; then return 0; fi
    done
    return 1
) }

Essa função geralmente é útil se você deseja excluir funções e recursos internos e procurar o nome $PATH. A maioria dos shells possui um built-in para isso, command -vembora seja uma adição relativamente recente ao POSIX (ainda opcional a partir do POSIX: 2004). É basicamente uma versão amigável do programador type: imprime o caminho completo de um executável $PATH, o nome simples de um built-in ou função e uma definição de alias para um alias.

exists_in_path () {
  case $(command -v -- "$1") in
    /*) return 0;;
    alias\ *) return 1;; # alias
    *) return 1;; # built-in or function
  esac
}

Ksh, bash e zsh também precisam type -pprocurar apenas executáveis ​​no $PATH. Observe que, no bash, o status de retorno type -p fooé 0 se foofor uma função ou função interna; se você quiser testar um executável $PATH, precisará verificar se a saída não está vazia. type -pnão está no POSIX; por exemplo, o ash do Debian (que está /bin/shno Ubuntu) não o possui.

Gilles 'SO- parar de ser mau'
fonte
@ Gilles, isso (ou algo semelhante) if [ type keychain ]; thennão funciona? Recebo erro /home/xenoterracide/.zshrc:84: parse error: condition expected: typeAcho que eu poderia escrever a função existe ... Eu apenas pensei que isso poderia ser mais simples em um sentido ...
xenoterracide
@xenoterracide: Largue os suportes!
Gilles 'SO- stop be evil'
Eu acho que você está procurando if type $APP >/dev/null 2>/dev/null; then ...Você não quer o [].
Steven D
4
Bah, eu sabia que deveria ter me refrescado. Batido por Gilles novamente!
Steven D
type -pse você estiver procurando especificamente por um comando $PATH(não aliases, funções ou componentes internos).
ephemient
1

Se você estiver procurando apenas programas externos, também poderá usar quais. Não sei como isso é portátil.

Kim
fonte
3
Em teoria, é menos portátil que typeou command; whichnão está no POSIX, por exemplo. Na prática, whichexiste quase em toda parte, mas em alguns lugares (onde é implementado como um script csh), ele usa um caminho diferente (devido a .cshrc), que derrota o objetivo.
Gilles 'SO- stop be evil'