O Comando `which` no Linux: Guia Técnico Completo com Exemplos
O comando `which` no Linux localiza o caminho absoluto de um executável ao percorrer os diretórios listados na variável de ambiente `PATH` e retornando a primeira correspondência encontrada. É um utilitário adjacente ao POSIX usado diariamente por administradores de sistemas, desenvolvedores e engenheiros DevOps para verificar localizações de binários, auditar ambientes de execução e depurar conflitos relacionados ao PATH.
Quando você executa `which python3`, o shell não pesquisa todo o sistema de arquivos — ele percorre apenas a lista de diretórios delimitada por dois pontos armazenada em `$PATH`, da esquerda para a direita, e para na primeira correspondência. Esse comportamento é tanto o seu maior ponto forte quanto a sua limitação mais importante a ser compreendida.
Sintaxe Básica
“`bash
which [options] command_name [command_name …]
“`
- `[options]` — Flags opcionais que modificam o comportamento da saída (abordadas em detalhes abaixo).
- `command_name` — Um ou mais nomes de executáveis que você deseja localizar.
Como o `which` Funciona Internamente
Quando você invoca `which`, ele lê o valor atual da variável de ambiente `PATH`, divide-a nos delimitadores `:` e itera por cada diretório em ordem. Para cada diretório, verifica se existe um arquivo correspondente ao nome do comando e se ele tem o bit executável definido (permissão `x`). A primeira correspondência é impressa na saída padrão.
Isso significa que `which` é totalmente dependente do estado de execução atual de `$PATH`. Se o seu `PATH` estiver mal configurado — por exemplo, um diretório personalizado aparece após `/usr/bin` em vez de antes — `which` refletirá essa má configuração exatamente, o que é precisamente por que é útil para depuração.
Para inspecionar seu `PATH` atual:
“`bash
echo $PATH
Example output:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
“`
Casos de Uso Principais e Exemplos
Exemplo 1: Localizar um Único Executável
O uso mais fundamental é encontrar onde um binário reside:
“`bash
which python3
“`
“`
/usr/bin/python3
“`
Isso confirma que quando você digita `python3`, o sistema executa `/usr/bin/python3`. Se você compilou uma versão personalizada e a colocou em `/opt/python3.12/bin/`, mas esse diretório não está em `PATH`, `which` não o encontrará.
Exemplo 2: Consultar Múltiplos Comandos em Uma Única Execução
Você pode passar múltiplos nomes de comandos em uma única invocação, o que é eficiente ao auditar um ambiente de build:
“`bash
which python3 gcc git curl wget
“`
“`
/usr/bin/python3
/usr/bin/gcc
/usr/bin/git
/usr/bin/curl
/usr/bin/usr/bin/wget
“`
Isso é particularmente útil em scripts de validação de pipeline CI/CD, onde você precisa confirmar que todas as ferramentas necessárias estão presentes antes de um build começar.
Exemplo 3: Descobrir Todas as Instâncias com `-a`
A flag `-a` instrui o `which` a continuar pesquisando após a primeira correspondência e reportar cada instância encontrada em todos os diretórios `PATH`:
“`bash
which -a python3
“`
“`
/usr/bin/python3
/usr/local/bin/python3
“`
Isso é crítico em ambientes onde múltiplas versões do Python estão instaladas — por exemplo, um Python do sistema em `/usr/bin/python3` e uma versão gerenciada pelo pyenv em `/usr/local/bin/python3`. O binário que aparece primeiro em `PATH` é o que será executado. Se a versão errada estiver ativa, esta saída informa exatamente onde o conflito se origina.
Caso extremo do mundo real: Em servidores que executam tanto um Node.js empacotado pela distribuição quanto um Node.js gerenciado pelo nvm, `which -a node` frequentemente revela dois ou três caminhos conflitantes. Resolver isso requer reordenar as entradas `PATH` em `.bashrc` ou `.zshrc`, não reinstalar o software.
Exemplo 4: Comportamento de Resolução de Alias
O comportamento do `which` com aliases depende muito do shell e da implementação específica do `which` instalada no sistema.
Em muitas distribuições Linux, `which` é um binário externo independente (não um built-in do shell), portanto não tem acesso à tabela de aliases do shell atual. No entanto, em sistemas onde `which` é implementado como uma função de shell ou alias em si (comum em configurações zsh), ele pode resolver aliases:
“`bash
alias ls='ls –color=auto'
which ls
“`
Em um sistema zsh com o `which` baseado em função:
“`
ls: aliased to ls –color=auto
“`
Em um sistema bash com o binário externo `which`:
“`
/bin/ls
“`
Essa inconsistência é uma fonte bem conhecida de confusão e é uma das principais razões pelas quais administradores experientes preferem `type` ou `command -v` em scripts (discutido abaixo).
Exemplo 5: Usando `which` em Lógica Condicional de Scripts
Um padrão comum em scripts de shell é usar `which` para verificar uma dependência antes de prosseguir:
“`bash
if ! which docker > /dev/null 2>&1; then
echo "Docker is not installed or not in PATH. Aborting."
exit 1
fi
“`
No entanto, a abordagem mais portável e compatível com POSIX para scripts é `command -v`:
“`bash
if ! command -v docker > /dev/null 2>&1; then
echo "Docker not found."
exit 1
fi
“`
A distinção importa ao escrever scripts destinados a executar em múltiplas distribuições ou shells.
`which` vs. `type` vs. `command -v`: Uma Comparação Técnica
Essas três ferramentas atendem a necessidades sobrepostas, mas distintas. Escolher a errada para o trabalho leva a bugs sutis, especialmente em scripts de shell.
| Funcionalidade | `which` | `type` | `command -v` |
|---|
| — | — | — | — |
|---|
| Localiza binários externos | Sim | Sim | Sim |
|---|
| Resolve aliases do shell | Dependente da implementação | Sim (sempre) | Sim (sempre) |
|---|
| Resolve funções do shell | Não | Sim | Sim |
|---|
| Identifica built-ins do shell | Não | Sim | Sim |
|---|
| Compatível com POSIX | Não | Sim | Sim |
|---|
| Funciona de forma confiável em scripts | Arriscado | Arriscado (built-in bash) | Recomendado |
|---|
| Formato de saída | Apenas caminho | String descritiva | Caminho ou definição |
|---|
| Pesquisa todas as entradas PATH (equivalente a `-a`) | Sim (com `-a`) | Sim (com `-a`) | Não |
|---|
| Binário externo (não um built-in) | Sim | Não (built-in) | Não (built-in) |
|---|
Orientação prática:
- Use `which` interativamente no terminal quando precisar de uma consulta rápida de caminho.
- Use `type -a` quando quiser ver todas as formas que um comando assume (alias, função, built-in e binário).
- Use `command -v` em scripts de shell em produção para portabilidade POSIX.
`type` em Ação
“`bash
type -a python3
“`
“`
python3 is /usr/bin/python3
python3 is /usr/local/bin/python3
“`
“`bash
type ls
“`
“`
ls is aliased to `ls –color=auto'
“`
`command -v` em Ação
“`bash
command -v git
“`
“`
/usr/bin/git
“`
“`bash
command -v ll
“`
“`
ll: aliased to ls -alF
“`
Cenários Práticos de Depuração
Depurando uma Versão Incorreta do Python
Um desenvolvedor relata que `python3 –version` retorna `3.9.x` mas ele instalou `3.11` através de uma compilação personalizada. A sequência de diagnóstico:
“`bash
which python3 # Shows the first match
which -a python3 # Shows all matches
echo $PATH # Reveals directory ordering
ls -la /usr/local/bin/python3 # Checks if the custom build is symlinked correctly
“`
A correção é quase sempre um symlink ausente ou um problema de ordenação do `PATH` no arquivo de inicialização do shell.
Diagnosticando um Comando Ausente Após a Instalação
Se `which curl` não retornar nenhuma saída, o binário não está instalado ou foi instalado em um diretório fora do `PATH`. Distingua entre esses casos:
“`bash
which curl # No output = not in PATH
find /usr -name curl -type f 2>/dev/null # Search for the binary outside PATH
apt list –installed 2>/dev/null | grep curl # Check package manager
“`
Verificando Caminhos de Ferramentas Antes da Implantação
Ao configurar um novo ambiente de VPS Hosting, uma lista de verificação pré-implantação padrão deve incluir a execução de `which -a` em cada binário crítico do qual sua aplicação depende. Isso detecta desvios de ambiente entre desenvolvimento, staging e produção antes que causem falhas em tempo de execução.
Limitações Conhecidas do `which`
Compreender essas limitações evita diagnósticos incorretos em ambientes complexos:
- Escopo apenas do `PATH`: `which` é cego a qualquer executável não acessível através do `$PATH`. Ferramentas instaladas em diretórios locais do usuário como `~/.local/bin` só serão encontradas se esse diretório estiver no `PATH`.
- Sem consciência de built-ins do shell: Comandos como `cd`, `echo`, `alias` e `source` são built-ins do shell. `which cd` não retornará nada ou retornará um caminho para um binário externo `cd` raramente usado, dando um resultado enganoso.
- Tabelas de alias específicas do shell: `which` como binário externo não pode ler a tabela de aliases do shell chamador. Isso o torna não confiável para introspecção de aliases no bash.
- Transparência de symlinks: `which` reporta o caminho do symlink, não o destino resolvido. Se `/usr/bin/python3` é um symlink para `/usr/bin/python3.11`, `which python3` mostra `/usr/bin/python3`. Use `readlink -f $(which python3)` para resolver a cadeia completa.
- Contexto `sudo`: Executar um comando com `sudo` usa o `PATH` do root, que pode diferir significativamente do `PATH` do seu usuário. `which node` como usuário regular pode retornar um caminho diferente de `sudo which node`.
Padrões Avançados
Resolver a Cadeia Completa de Symlinks
“`bash
readlink -f $(which python3)
Output: /usr/bin/python3.11
“`
Verificar Permissões de Executável Junto com o Caminho
“`bash
ls -la $(which nginx)
Output: -rwxr-xr-x 1 root root 1234567 Jan 10 2024 /usr/sbin/nginx
“`
Combinar com `xargs` para Inspeção em Lote
“`bash
echo "python3 gcc git" | xargs -n1 which
“`
Usar em Scripts de Validação de Ambiente
Em um Servidor Dedicado executando uma pilha de aplicações complexa, um script de validação de inicialização pode ser assim:
“`bash
#!/bin/bash
REQUIRED_BINS="nginx php-fpm mysql redis-cli composer"
MISSING=0
for bin in $REQUIRED_BINS; do
if ! command -v "$bin" > /dev/null 2>&1; then
echo "MISSING: $bin"
MISSING=$((MISSING + 1))
else
echo "OK: $bin -> $(which $bin)"
fi
done
[ "$MISSING" -gt 0 ] && exit 1
exit 0
“`
Notas sobre Comportamento Específico do Shell
O comportamento do `which` não é uniforme em todos os ambientes Linux:
- Bash: `which` é tipicamente um binário externo (`/usr/bin/which`). Ele não vê aliases ou funções do bash a menos que sejam exportados.
- Zsh: Muitas configurações zsh incluem `which` como uma função built-in do shell que resolve aliases e funções, tornando sua saída mais rica, mas também diferente do comportamento do bash.
- Fish shell: O Fish tem seu próprio equivalente ao `which` integrado, e seu sistema de aliases (chamado `functions`) é tratado de forma diferente.
- Alpine Linux / ambientes BusyBox: O utilitário `which` é fornecido pelo BusyBox e pode ter um conjunto de funcionalidades reduzido em comparação com o pacote GNU `which`.
Essa variabilidade é especialmente relevante ao gerenciar aplicações em contêineres ou configurar Painéis de Controle VPS onde o shell subjacente pode diferir do seu ambiente de desenvolvimento local.
Considerações de Segurança
Em ambientes sensíveis à segurança, `which` pode ser usado como uma ferramenta de auditoria leve:
- Verificar se binários privilegiados como `sudo`, `su` ou `passwd` resolvem para caminhos de sistema esperados e não para diretórios graváveis pelo usuário anteriores no `PATH`.
- Detectar tentativas de sequestro de PATH: se `which ls` retornar `/home/user/bin/ls` em vez de `/bin/ls`, um binário malicioso pode ter sido injetado.
“`bash
Audit critical system binaries
for cmd in sudo su passwd ssh scp; do
echo "$cmd -> $(which $cmd)"
done
“`
Este é um passo padrão ao fortalecer um servidor que hospedará Certificados SSL ou lidará com terminação TLS sensível, onde a integridade do binário é inegociável.
Ao gerenciar ambientes de Hospedagem Web Compartilhada com múltiplos usuários, verificar se diretórios graváveis pelo usuário não aparecem antes dos diretórios do sistema no `PATH` de qualquer usuário é um controle de segurança importante.
Matriz de Decisão: Quando Usar Qual Ferramenta
| Cenário | Ferramenta Recomendada |
|---|
| — | — |
|---|
| Consulta rápida interativa de caminho | `which` |
|---|
| Script: verificar se um comando existe | `command -v` |
|---|
| Identificar se um comando é um alias ou função | `type` |
|---|
| Encontrar todas as instâncias no PATH | `which -a` ou `type -a` |
|---|
| Resolver symlinks para o binário final | `readlink -f $(which …)` |
|---|
| Auditar sequestro de PATH | `which` + inspeção manual do PATH |
|---|
| Scripts portáveis entre shells | `command -v` |
|---|
Principais Conclusões Técnicas
- `which` pesquisa o `$PATH` da esquerda para a direita e retorna a primeira correspondência executável — a ordenação das entradas `PATH` determina diretamente qual binário é executado.
- A flag `-a` é essencial quando múltiplas versões de uma ferramenta coexistem; nunca assuma que existe apenas uma instância sem verificar.
- Não use `which` em scripts de shell em produção — use `command -v` para conformidade com POSIX e comportamento consistente entre bash, dash e zsh.
- `which` não pode ver built-ins do shell, funções ou aliases definidos na sessão atual do shell quando é executado como binário externo.
- Sempre complemente um resultado de `which` com `readlink -f` quando symlinks estiverem envolvidos para identificar o binário real sendo executado.
- Em ambientes multiusuário ou em contêineres, `PATH` difere entre usuários e entre contextos `sudo` e não-`sudo` — sempre verifique no contexto correto.
- O sequestro de PATH através de diretórios graváveis pelo usuário adicionados ao início do `$PATH` é um vetor de ataque real; `which` é uma ferramenta de auditoria rápida de primeira linha contra isso.
Perguntas Frequentes
Qual é a diferença entre `which` e `whereis`?
`which` pesquisa apenas o `$PATH` por executáveis. `whereis` pesquisa um conjunto mais amplo de diretórios de sistema predefinidos para o binário, sua página de manual e seus arquivos de código-fonte simultaneamente. Use `whereis` quando precisar localizar documentação ou código-fonte junto com o binário.
Por que `which cd` não retorna nada?
`cd` é um built-in do shell, não um executável externo. Como `which` só verifica o `$PATH` por arquivos com permissão de execução, ele não consegue encontrar comandos built-in. Use `type cd` em vez disso, que reportará corretamente `cd is a shell builtin`.
O `which` pode me dizer qual versão de um programa está instalada?
Não. `which` retorna apenas o caminho. Para obter a versão, redirecione o resultado: `$(which python3) –version` ou simplesmente `python3 –version`. O caminho do `which` ajuda a confirmar que você está consultando o binário correto.
Por que `which python3` retorna um resultado diferente quando uso `sudo`?
`sudo` executa comandos com o ambiente do root, incluindo o `PATH` do root, que é tipicamente mais restritivo do que o `PATH` de um usuário regular. Diretórios como `~/.local/bin` ou caminhos nvm/pyenv adicionados ao `.bashrc` de um usuário estão ausentes do `PATH` do root. Sempre teste com `sudo which python3` separadamente ao depurar execução com privilégios elevados.
O `which` está disponível no macOS?
Sim, o macOS inclui `which` como parte de seu userland derivado do BSD. No entanto, a versão do macOS não suporta a flag `-a` em todas as versões mais antigas. No macOS moderno com Homebrew, você pode ter o GNU `which` instalado junto com a versão do sistema. Use `type -a which` no macOS para ver qual implementação está ativa.
