Linux / Comando which: encontrar executáveis e conferir a ordem do PATH

O comando which procura um executável nos diretórios de PATH e mostra o caminho encontrado. Ele ajuda a conferir qual instalação de um programa vem primeiro nessa lista, mas não descreve sozinho a escolha completa do shell. Para identificar funções, aliases e comandos internos, consulte também type ou command -v.

Os exemplos usam Bash, o executável externo do GNU which e utilitários como mktemp e chmod. A prática cria três scripts pequenos em uma pasta exclusiva. As mudanças em PATH, funções e cache de comandos ficam dentro de subshells, delimitados por parênteses, e terminam ao sair de cada bloco; não é necessário editar arquivos de configuração do shell.

Entender o que o which pesquisa

PATH é uma lista de diretórios separados por dois-pontos nos sistemas Unix. Na busca usual, o GNU which considera a ordem da esquerda para a direita e mostra o primeiro executável correspondente; -a pede todas as correspondências. Um arquivo fora dessa lista pode estar instalado e ainda assim não aparecer. Além disso, o nome which pode ser uma função ou alias que envolve outro programa. Antes da prática, confira type -a which, localize o executável externo e confirme que sua versão é GNU which.

Sintaxe básica

which [opções]... [--] comando...

opções e comando são marcadores. Consulte which --help e man which na instalação de destino; as opções GNU não são universais. Um nome sem barra, como python3, provoca a busca em PATH. Um caminho explícito, como ./programa, é outro caso: não serve para comparar todas as instalações desse nome em PATH. Não execute um arquivo desconhecido apenas para descobrir onde ele está.

Uso básico do which

Preparar executáveis e encontrar o primeiro caminho

Use uma pasta cujo caminho não contenha dois-pontos, pois esse caractere separa entradas de PATH. Execute o bloco no mesmo terminal e pare se algum comando falhar. which_bin guarda o caminho do executável externo de which encontrado pelo Bash, permitindo chamá-lo diretamente em vez de um wrapper de mesmo nome. O bloco cria first/which_demo_tool, second/which_demo_tool e first/which_demo_helper. A consulta final deve apontar para /first/which_demo_tool dentro da pasta exclusiva. Os scripts só imprimem textos conhecidos.

which_bin=$(type -P which) &&
"$which_bin" --version &&
which_demo=$(mktemp -d -p "$PWD" 'which-demo.XXXXXXXX') &&
mkdir -- "$which_demo/first" "$which_demo/second" &&
printf '%s\n' '#!/bin/sh' 'printf "primeiro\n"' > "$which_demo/first/which_demo_tool" &&
printf '%s\n' '#!/bin/sh' 'printf "segundo\n"' > "$which_demo/second/which_demo_tool" &&
printf '%s\n' '#!/bin/sh' 'printf "auxiliar\n"' > "$which_demo/first/which_demo_helper" &&
chmod +x -- "$which_demo/first/which_demo_tool" \
  "$which_demo/second/which_demo_tool" "$which_demo/first/which_demo_helper" &&
(
  PATH="$which_demo/first:$which_demo/second:$PATH"
  export PATH
  "$which_bin" -- which_demo_tool
)

Consultar vários nomes

O exemplo procura os dois nomes fictícios em uma única chamada: ambos vêm da pasta first. Quando um dos nomes não é encontrado, o GNU which pode imprimir os caminhos dos demais e ainda retornar um estado não zero. Ver uma linha de sucesso não comprova que todos os argumentos foram encontrados. Para consultar ferramentas reais, a mesma ideia vale para uma chamada como which sh awk sed, desde que a implementação e esses programas estejam disponíveis.

(
  PATH="$which_demo/first:$which_demo/second:$PATH"
  export PATH
  "$which_bin" -- which_demo_tool which_demo_helper
)

Listar todas as correspondências

A opção -a deve mostrar dois caminhos para which_demo_tool, primeiro em first e depois em second. Sem -a, somente o primeiro é mostrado. Esses caminhos não significam que duas versões diferentes estejam necessariamente instaladas: diretórios repetidos, links simbólicos e diferentes nomes para o mesmo local também podem produzir resultados relacionados. Compare os caminhos e o contexto antes de concluir que há instalações independentes.

(
  PATH="$which_demo/first:$which_demo/second:$PATH"
  export PATH
  "$which_bin" -a -- which_demo_tool
)

Comparar o caminho externo com uma função do shell

Neste bloco, a função which_demo_tool existe somente no subshell e tem prioridade sobre os scripts externos. O GNU which continua encontrando o arquivo de first, mas chamar which_demo_tool executa a função e imprime funcao. Para tornar a saída abaixo reproduzível, o printf remove apenas o prefixo da pasta exclusiva do caminho retornado; o which em si informa o caminho completo.

(
  PATH="$which_demo/first:$which_demo/second:$PATH"
  export PATH
  which_demo_tool() { printf 'funcao\n'; }
  caminho=$("$which_bin" -- which_demo_tool) &&
  printf '%s\n' "${caminho#"$which_demo"/}" &&
  which_demo_tool
)

Saída esperada desse bloco:

first/which_demo_tool
funcao

O contraste mostra por que um caminho encontrado não é uma descrição completa da resolução do shell. As ferramentas type, command -V e command -v consultam o contexto do shell em que são executadas. Rodá-las em outro processo ou em outro terminal pode produzir uma resposta diferente, pois os aliases, as funções, o PATH e o cache podem ser outros.

Principais opções do GNU which

Opção Efeito no GNU which
-a, --all Mostrar todas as correspondências em PATH, em vez de somente a primeira.
--read-alias Ler definições de aliases pela entrada padrão. Não consultar automaticamente o estado interno do shell chamador.
--skip-alias Ignorar --read-alias, quando essa opção tiver sido fornecida por um wrapper ou pela chamada.
--read-functions Ler definições de funções pela entrada padrão e informar as correspondentes.
--skip-functions Ignorar --read-functions. Não remover nem desativar as funções do shell.
--version Mostrar a versão do executável consultado; confirme também se o nome which é um wrapper.

Exemplos práticos

Inverter a prioridade sem mudar o terminal principal

Aqui second vem antes de first somente dentro dos parênteses. O -a deve listar second e depois first; executar o nome fictício deve imprimir segundo. hash -r limpa a tabela de caminhos lembrados desse subshell para que a comparação comece sem um caminho em cache. A tabela e o PATH do terminal principal não são modificados. Não acrescente a pasta atual ou diretórios que outras pessoas possam alterar ao PATH só para fazer um programa aparecer.

(
  PATH="$which_demo/second:$which_demo/first:$PATH"
  export PATH
  hash -r
  "$which_bin" -a -- which_demo_tool
  which_demo_tool
)

Pedir ao Bash a classificação do nome

A função deste subshell mantém o nome de demonstração. type -a deve mostrar a função e os caminhos externos; command -V dá uma descrição da resolução, e command -v informa o nome pelo qual o shell a invoca. Para a função, a resposta curta é which_demo_tool, não o caminho de um dos scripts. type -t printf deve indicar builtin em um Bash sem redefinições desse nome. Consulte o manual dos comandos internos do Bash; o texto descritivo pode variar com o idioma e a versão.

(
  PATH="$which_demo/first:$which_demo/second:$PATH"
  export PATH
  which_demo_tool() { printf 'funcao\n'; }
  type -a which_demo_tool
  command -V which_demo_tool
  command -v which_demo_tool
  type -t printf
)

Testar disponibilidade pelo estado de saída

O exemplo usa o estado de command -v, sem interpretar sua saída, e deve imprimir comando disponivel nesta preparação. Essa forma de teste também se aplica a nomes reais como curl e é adequada a scripts de shell que precisam de uma verificação básica. Ela pode aceitar uma função ou comando interno com o mesmo nome: se a exigência for um executável externo específico, faça uma verificação compatível com essa exigência. Encontrar o nome não comprova versão, recursos, dependências nem que uma operação de rede funcionará.

(
  PATH="$which_demo/first:$which_demo/second:$PATH"
  export PATH
  if command -v which_demo_tool >/dev/null 2>&1; then
    printf '%s\n' 'comando disponivel'
  else
    printf '%s\n' 'comando indisponivel' >&2
  fi
)

Comparar which, command, type e whereis

Comando Função principal Quando usar
which Consultar executáveis em PATH Conferir caminhos e sua ordem, considerando o wrapper e a implementação
command -v Informar a resolução pelo shell Testar disponibilidade sem analisar uma descrição extensa
type Classificar nomes e, no Bash, listar alternativas Distinguir alias, função, comando interno e arquivo
whereis Pesquisar locais relacionados a programas Localizar binários, fontes e manuais em seus caminhos de busca

Cuidados importantes

Distinguir wrappers e o executável externo

Algumas configurações fornecem ao GNU which uma lista produzida por alias ou declare -f. Nessa situação, o which pode mostrar definições de aliases e funções, em vez de apenas caminhos. As opções --skip-alias e --skip-functions apenas controlam essa leitura pelo programa; não fazem o shell ignorar aliases ou funções quando você executa o nome consultado. Confira type -a which antes de interpretar a saída e use type ou command no shell de interesse.

Verificar PATH e caminhos lembrados

Um terminal interativo, um serviço e uma tarefa agendada podem ter PATH diferentes. No Bash, a tabela hash também pode guardar um caminho para um comando já usado; em um diagnóstico, hash -t NOME mostra a entrada lembrada e hash -r a limpa. type -a ajuda a comparar alternativas no contexto atual. Não altere configurações permanentes sem identificar primeiro por que um caminho foi escolhido. Ao final, a pasta de prática pode permanecer para consulta; nenhum arquivo do sistema precisa ser substituído.

Conferir o arquivo e a finalidade da verificação

Um caminho encontrado não valida a origem, a integridade nem a finalidade do arquivo. Verificações de proprietário e permissões, quando necessárias, têm outro objetivo e dependem do sistema; which não as transforma em uma garantia de confiança. Em automações, examine também o estado de saída e as mensagens de erro. No GNU which, o estado informa quantos argumentos não foram encontrados, segundo o manual do autor; não trate todo estado não zero como uma confirmação de que nenhum dos nomes existe.

Perguntas frequentes

Nenhuma saída significa que o programa não está instalado?

Não necessariamente. O executável pode estar fora de PATH, não ser acessível como esperado ou o nome pode corresponder a uma função, alias ou comando interno. Confira as mensagens de erro, type e command -v no shell em que pretende usar o nome.

Como mostrar todos os caminhos correspondentes?

No GNU which, use which -a NOME. Confirme o suporte em outras implementações. A ordem segue a busca em PATH, mas um wrapper pode acrescentar informações de aliases e funções, e caminhos diferentes podem referir-se ao mesmo local.

Qual teste usar em scripts?

Para uma verificação básica pelo shell, use o estado de command -v NOME >/dev/null 2>&1 dentro de uma condição. Esse teste pode reconhecer funções e comandos internos; se precisar de um arquivo externo ou de uma versão específica, verifique esse requisito separadamente.

Qual é a diferença para whereis?

which busca executáveis em PATH. whereis procura arquivos relacionados a programas, como binários, fontes e manuais, nos locais que ele consulta. Uma localização encontrada por whereis não demonstra que o shell executará aquele arquivo ao receber apenas o nome.