Corrigindo "bad interpreter" - Problemas de Shebang e CRLF

Corrigindo "bad interpreter" - Problemas de Shebang e CRLF

O que e o erro "bad interpreter"?

Conclusao: O shell nao consegue executar o interpretador indicado na linha shebang do script. Quase todos os casos sao terminacoes de linha CRLF ou um caminho shebang errado.

Voce tenta executar um shell script e encontra um erro como este:

$ ./deploy.sh
-bash: ./deploy.sh: cannot execute: required file not found

O arquivo existe e tem permissao de execucao, mas se recusa a rodar. Este erro significa que o kernel nao consegue iniciar o interpretador declarado na linha 1 (o #!... shebang).

A mensagem acima e o que o bash 5.1 e posteriores exibem (Ubuntu 22.04+, Debian 11+, RHEL 9+, etc.). No bash 5.0 e anteriores (Ubuntu 20.04, Debian 10, RHEL 8, etc.) voce ve o caminho do interpretador e um ^M (CR), como -bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory. A causa e identica em ambos os casos.

Reduza a duas causas primeiro

Quase sempre e uma de duas coisas:

  • Terminacoes de linha CRLF se infiltraram (mais comum)
  • O caminho do shebang nao existe

No bash 5.1 e posteriores ambas produzem o mesmo cannot execute: required file not found, entao o texto do erro sozinho nao consegue diferencia-las. Nao confie na mensagem; observe o arquivo diretamente com file e cat -A (abaixo) para decidir.

Note que Permission denied e um problema diferente: falta do bit de execucao (chmod +x). E facil confundir os dois, entao para o lado da permissao veja Corrigindo Permission denied.

Por que diz que nao encontra o interpretador?

Conclusao: O kernel usa a linha shebang literalmente como caminho do interpretador. Um \r final do CRLF transforma /bin/bash em /bin/bash\r, um caminho que nao existe. O bash 5.1 e posteriores reportam como cannot execute: required file not found; o bash 5.0 e anteriores reportam como No such file or directory.

O kernel Linux le a primeira linha comecando com #! e trata o texto apos #! literalmente, como o caminho absoluto para um interpretador. Essa e a raiz do erro.

Arquivos salvos no Windows ou por alguns editores usam terminacoes de linha CRLF (\r\n) em vez de LF (\n). A linha shebang e entao lida como:

#!/bin/bash\r
       este \r (CR) faz parte do "caminho"

Entao o kernel procura um arquivo literalmente chamado /bin/bash + retorno de carro. Esse arquivo nao existe, entao falha. O bash 5.1 e posteriores exibem cannot execute: required file not found; o bash 5.0 e anteriores exibem No such file or directory e mostram o CR como ^M (o ^M so aparece na mensagem do bash 5.0 e anteriores).

Mesmo quando o nome e o caminho estao corretos, um unico \r invisivel quebra tudo. Por isso a linha "parece certa mas nao roda."

O caminho do shebang em si tambem pode estar errado. Por exemplo, voce escreveu #!/usr/local/bin/python3 mas o Python so existe em /usr/bin/python3 naquela maquina.

Como saber se CRLF e a causa?

Conclusao: Use file para detectar o tipo de terminacao de linha e cat -A para revelar ^M no final das linhas. Ambos expoe CRLF rapidamente.

Observe a causa antes de corrigir qualquer coisa.

Verificar terminacoes de linha com file

$ file deploy.sh

Quando CRLF esta presente, voce ve:

deploy.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

with CRLF line terminators confirma que terminacoes de linha sao a causa. Um arquivo limpo mostra apenas ASCII text executable sem nota de CRLF.

Revelar finais de linha com cat -A

$ cat -A deploy.sh | head -3
#!/bin/bash^M$
^M$
echo "deploy start"^M$

cat -A marca finais de linha com $ e CR com ^M. Se toda linha termina com ^M$, e CRLF. Um arquivo limpo mostra apenas $.

Inspecionar a linha shebang com precisao

$ head -1 deploy.sh | od -c
0000000   #   !   /   b   i   n   /   b   a   s   h  \r  \n

\r \n juntos significa CRLF. \n sozinho significa LF (limpo).

Como corrigir terminacoes de linha CRLF?

Conclusao: dos2unix e a correcao mais confiavel. Sem ele, use sed -i 's/\r$//' para remover o CR final de cada linha, depois re-verifique com file.

Opcao 1: dos2unix (recomendado)

$ dos2unix deploy.sh
dos2unix: converting file deploy.sh to Unix format...

Uma ferramenta dedicada que converte CRLF para LF. Instale com sudo apt install dos2unix no Ubuntu/Debian ou sudo dnf install dos2unix em sistemas baseados em RHEL.

Opcao 2: sed (sem instalacao extra)

Se dos2unix nao estiver disponivel, sed resolve.

$ sed -i 's/\r$//' deploy.sh

s/\r$// significa "excluir o CR no final de cada linha." -i edita o arquivo in-place. Use -i.bak para manter um backup por precaucao.

$ sed -i.bak 's/\r$//' deploy.sh   # mantem deploy.sh.bak

Com tr -d '\r', tr so le da entrada padrao, entao voce nao pode redirecionar de volta para o mesmo arquivo (ele ficaria vazio). Sempre escreva em um arquivo diferente.

$ tr -d '\r' < deploy.sh > deploy.unix.sh   # OK
$ tr -d '\r' < deploy.sh > deploy.sh         # ERRADO: acaba vazio

Opcao 3: converter no vim

Se o arquivo ja esta aberto em um editor, corrija in-place.

:set fileformat=unix
:w

Sempre confirme a correcao

$ file deploy.sh
deploy.sh: Bourne-Again shell script, ASCII text executable
$ ./deploy.sh
deploy start

Se a nota CRLF line terminators desapareceu, esta feito.

Como corrigir um caminho shebang errado?

Conclusao: Confirme que o interpretador realmente existe no caminho do shebang com which. Para portabilidade, use #!/usr/bin/env bash.

Este e o caso em que nenhum interpretador existe no caminho do shebang. No bash 5.0 e anteriores a mensagem mostra o caminho problematico, como bash: ./run.sh: /usr/local/bin/python3: bad interpreter. No bash 5.1 e posteriores um caminho ausente e CRLF parecem identicos -- ambos exibem cannot execute: required file not found sem mostrar o caminho. Em ambas as versoes, nao confie no texto do erro: descarte CRLF com file / cat -A, depois confirme se o interpretador existe com which.

Confirme que o interpretador existe

$ head -1 run.sh
#!/usr/local/bin/python3
$ which python3
/usr/bin/python3

O shebang aponta para /usr/local/bin/python3, mas o binario real esta em /usr/bin/python3. Os caminhos divergem.

Resolva com env

Em vez de fixar o caminho real, deixe env encontrar o interpretador no PATH para melhor portabilidade.

#!/usr/bin/env python3
#!/usr/bin/env bash

env busca o interpretador no PATH, entao o script funciona independente de o binario estar em /usr/bin ou /usr/local/bin. E a forma moderna e resiliente ao ambiente.

Note que passar argumentos para o interpretador atraves de env e limitado (sistemas mais antigos nao suportam multiplos argumentos). Opcoes como set -euo pipefail pertencem ao corpo do script, nao ao shebang.

Como evitar que volte a acontecer?

Conclusao: Fixe arquivos .sh como LF com .gitattributes e configure seu editor para salvar como LF. Esses dois passos bloqueiam quase toda reintroducao de CRLF.

Corrigir uma vez e inutil se CRLF volta a cada save ou commit. Corte na origem.

Fixar terminacoes de linha no Git

Coloque um .gitattributes na raiz do repositorio e fixe shell scripts como LF.

*.sh text eol=lf

Agora checkouts sempre usam LF, entao o arquivo sobrevive a edicoes de maquinas Windows.

Verifique tambem sua configuracao de core.autocrlf. No Linux/macOS, input e a escolha segura.

$ git config --global core.autocrlf input

core.autocrlf=true e comum entre desenvolvedores Windows, mas adiciona CRLF no checkout, criando condicoes para bad interpreter em shell scripts. Ao trabalhar com scripts, sobreponha explicitamente com eol=lf no .gitattributes.

Configure seu editor para salvar como LF

  • VS Code: clique no indicador CRLF no canto inferior direito e troque para LF. Adicione um .editorconfig com end_of_line = lf para automatizar
  • vim: salve com :set fileformat=unix
  • Windows Notepad: nao use para shell scripts (tende a adicionar CRLF)

Checklist final

  1. file script.sh nao mostra CRLF line terminators
  2. O caminho do shebang em head -1 script.sh resolve para um interpretador real via which
  3. ls -l script.sh mostra o bit de execucao (x) ativo

Com os tres em ordem, bad interpreter nao retornara.

Proximas leituras