"command not found" para seus proprios scripts - PATH e chmod

"command not found" para seus proprios scripts - PATH e chmod

O que voce vai aprender

  • Por que apenas o seu script diz command not found
  • Como diferenciar command not found de Permission denied
  • Como seguir na ordem ./, chmod +x, PATH e hash -r

Resumo rapido

command not found significa que o shell nao encontrou esse comando no seu PATH. Para seus proprios scripts, corrija nesta ordem:

  1. Execute do diretorio atual com ./script.sh (um nome simples so busca no PATH)
  2. Adicione o bit de execucao com chmod +x script.sh
  3. Adicione o diretorio ao PATH para uso diario (~/bin ou ~/.local/bin)
  4. Limpe o cache de caminhos com hash -r apos mover ou substituir o script

Premissas

  • Shell: bash (o padrao no Ubuntu / Debian)
  • Alvo: um script .sh que voce escreveu, ou um comando que voce compilou
  • zsh funciona da mesma forma; apenas detalhes como hash -r diferem

Por que apenas o meu script diz command not found?

Conclusao: O bash busca um nome de comando simples apenas nos diretorios listados no PATH. O diretorio atual nao esta no PATH por padrao, entao digitar script.sh nao encontra nada.

Quando voce digita script.sh, o bash resolve na seguinte ordem:

  1. Funcoes do shell, aliases e builtins
  2. Caminhos ja em cache no hash
  3. Os diretorios listados na variavel de ambiente PATH (do inicio ao fim)

Se script.sh nao esta em nenhum dos diretorios do PATH, voce recebe command not found mesmo que o arquivo esteja bem na sua frente.

$ ls
script.sh

$ script.sh
bash: script.sh: command not found

Deixar o diretorio atual (.) fora do PATH e um padrao de seguranca deliberado. Se . estivesse no inicio do PATH, um atacante poderia colocar um arquivo malicioso com nome de um comando real (ls) em um diretorio onde voce faz cd, e voce o executaria por acidente. Por isso um script "bem aqui" precisa ser nomeado explicitamente.

Qual a diferenca entre command not found e Permission denied?

Conclusao: command not found significa "nao localizado"; Permission denied significa "localizado, mas sem permissao de execucao." A mensagem indica qual caminho seguir.

Esses dois erros tem causas e correcoes diferentes.

Mensagem Significado Correcao principal
command not found Comando nao encontrado no PATH Usar ./ / adicionar ao PATH
Permission denied Arquivo existe mas sem bit de execucao chmod +x
bad interpreter Caminho shebang errado / terminacoes CRLF Corrigir shebang / dos2unix
# O caminho esta certo, mas nao ha permissao de execucao
$ ./script.sh
bash: ./script.sh: Permission denied

Se adicionar ./ muda o erro para Permission denied, o problema de PATH esta resolvido e a proxima questao sao permissoes. Se voce ve bad interpreter, o shebang ou terminacoes de linha estao com problema, entao leia Corrigindo "bad interpreter".

Execute com ./ primeiro

Conclusao: Execute um script no diretorio atual com ./script.sh. O ./ e um caminho explicito que pula a busca no PATH.

# NG: apenas o PATH e buscado, entao nao e encontrado
$ script.sh
bash: script.sh: command not found

# OK: nomeie o arquivo no diretorio atual diretamente
$ ./script.sh
Hello

Se esta em outro lugar, use um caminho absoluto ou relativo.

$ /home/alice/tools/script.sh
$ ~/tools/script.sh
$ bash script.sh        # passar ao bash funciona mesmo sem o bit de execucao

Passar o script para um interpretador (bash script.sh) o executa mesmo sem permissao de execucao. Isso e util para separar temporariamente um "problema de PATH" de um "problema de permissao."

O que acontece sem permissao de execucao?

Conclusao: Sem o bit de execucao, ./script.sh para com Permission denied. Conceda com chmod +x.

Scripts recem-criados, baixados ou copiados frequentemente perdem a permissao de execucao.

$ ls -l script.sh
-rw-r--r-- 1 alice alice 42 Jun  6 10:00 script.sh

$ ./script.sh
bash: ./script.sh: Permission denied

-rw-r--r-- nao tem x (bit de execucao). Adicione.

$ chmod +x script.sh
$ ls -l script.sh
-rwxr-xr-x 1 alice alice 42 Jun  6 10:00 script.sh

$ ./script.sh
Hello

chmod 777 e desnecessario e perigoso. Se voce so precisa executar o arquivo, chmod +x (ou chmod 755) e suficiente. Torna-lo gravavel por todos com 777 e um risco de seguranca.

Como adicionar meu diretorio ao PATH?

Conclusao: Para evitar digitar ./ toda vez, adicione o diretorio do seu script ao PATH. Coloque export PATH no ~/.bashrc para tornar permanente.

Primeiro, verifique o PATH atual.

$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin

Adicione o diretorio onde voce guarda seus scripts (por exemplo ~/bin).

# Apenas para esta sessao (shell atual)
$ export PATH="$HOME/bin:$PATH"

Para tornar permanente, adicione ao final de ~/.bashrc (ou ~/.profile para login shells).

# Adicionar ao final de ~/.bashrc
export PATH="$HOME/bin:$PATH"
# Recarregar no shell atual
$ source ~/.bashrc

$ which script.sh
/home/alice/bin/script.sh

$ script.sh        # executa sem ./
Hello

~/bin e ~/.local/bin

O ~/.profile padrao do Ubuntu adiciona ~/bin e ~/.local/bin ao PATH no login se eles existirem. Coloque seus scripts em qualquer um dos dois e o PATH geralmente funciona sem configuracao extra (pode ser necessario fazer login novamente para que tenha efeito).

Entradas do PATH sao separadas por :, e a posicao define a prioridade. Com $HOME/bin:$PATH seu script vence; com $PATH:$HOME/bin comandos existentes vencem. Para evitar sobrescrever acidentalmente um comando do sistema com o mesmo nome, adicione no final.

Ainda nao encontra, ou pega o binario antigo?

Conclusao: O bash armazena em cache o caminho de um comando uma vez que o encontra (hash). Logo apos mover ou substituir um script, ele pode usar o caminho antigo. Limpe o cache com hash -r.

Quando PATH e permissoes parecem corretos mas o comportamento esta errado, use type para ver o que o bash realmente pretende executar e de onde.

$ type -a script.sh
script.sh is /home/alice/bin/script.sh

Se type aponta para um local antigo, ou um comando que voce excluiu ainda executa, o cache esta desatualizado.

# Limpar caminhos de comandos em cache
$ hash -r

# Verificar novamente
$ type -a script.sh

which busca no PATH no sistema de arquivos, mas type reporta como o bash realmente resolve o nome, incluindo aliases, funcoes, builtins e o cache hash. Para diagnostico, type -a e a escolha confiavel.

Checklist

Conclusao: Siga "executar com ./ -> chmod +x -> adicionar ao PATH -> hash -r" e voce resolvera quase todo command not found dos seus proprios scripts.

Siga de cima para baixo.

  • [ ] Execute scripts no diretorio atual como ./script.sh
  • [ ] Verifique o bit de execucao (x) com ls -l; adicione com chmod +x se faltar
  • [ ] Permission denied significa problema de permissao, nao de PATH
  • [ ] Para uso diario, coloque scripts em ~/bin / ~/.local/bin ou adicione export PATH ao ~/.bashrc
  • [ ] Confirme que o diretorio aparece em echo $PATH
  • [ ] Se o comportamento estiver estranho apos mover/substituir, limpe o cache com hash -r
  • [ ] Confirme o alvo real com type -a script.sh

Proximas leituras: