Corrigindo "bad interpreter" - Problemas de Shebang e CRLF

Corrigindo "bad interpreter" - Problemas de Shebang e CRLF

O que é o erro "bad interpreter"?

Conclusão: O shell não consegue executar o interpretador indicado na linha shebang do script. Quase todos os casos são terminações de linha CRLF ou um caminho shebang errado.

Você 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 permissão de execução, mas se recusa a rodar. Este erro significa que o kernel não consegue iniciar o interpretador declarado na linha 1 (o #!... shebang).

A mensagem acima é 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.) você vê o caminho do interpretador e um ^M (CR), como -bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory. A causa é idêntica em ambos os casos.

Reduza a duas causas primeiro

Quase sempre é uma de duas coisas:

  • Terminações de linha CRLF se infiltraram (mais comum)
  • O caminho do shebang não existe

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

Note que Permission denied é um problema diferente: falta do bit de execução (chmod +x). É fácil confundir os dois, então para o lado da permissão veja Corrigindo Permission denied.

Por que diz que não encontra o interpretador?

Conclusão: 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 não 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 lê a primeira linha começando com #! e trata o texto após #! literalmente, como o caminho absoluto para um interpretador. Essa é a raiz do erro.

Arquivos salvos no Windows ou por alguns editores usam terminações de linha CRLF (\r\n) em vez de LF (\n). A linha shebang é então lida como:

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

Então o kernel procura um arquivo literalmente chamado /bin/bash + retorno de carro. Esse arquivo não existe, então 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 só aparece na mensagem do bash 5.0 e anteriores).

Mesmo quando o nome e o caminho estão corretos, um único \r invisível quebra tudo. Por isso a linha "parece certa mas não roda."

O caminho do shebang em si também pode estar errado. Por exemplo, você escreveu #!/usr/local/bin/python3 mas o Python só existe em /usr/bin/python3 naquela máquina.

Como saber se CRLF é a causa?

Conclusão: Use file para detectar o tipo de terminação de linha e cat -A para revelar ^M no final das linhas. Ambos expõe CRLF rapidamente.

Observe a causa antes de corrigir qualquer coisa.

Verificar terminações de linha com file

$ file deploy.sh

Quando CRLF está presente, você vê:

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

with CRLF line terminators confirma que terminações de linha são 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$, é CRLF. Um arquivo limpo mostra apenas $.

Inspecionar a linha shebang com precisão

$ 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 terminações de linha CRLF?

Conclusão: dos2unix é a correção mais confiável. Sem ele, use sed -i 's/\r$//' para remover o CR final de cada linha, depois re-verifique com file.

Opção 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.

Opção 2: sed (sem instalação extra)

Se dos2unix não estiver disponível, 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 precaução.

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

Com tr -d '\r', tr só lê da entrada padrão, então você não 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

Opção 3: converter no vim

Se o arquivo já está aberto em um editor, corrija in-place.

:set fileformat=unix
:w

Sempre confirme a correção

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

Se a nota CRLF line terminators desapareceu, está feito.

Como corrigir um caminho shebang errado?

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

Este é o caso em que nenhum interpretador existe no caminho do shebang. No bash 5.0 e anteriores a mensagem mostra o caminho problemático, como bash: ./run.sh: /usr/local/bin/python3: bad interpreter. No bash 5.1 e posteriores um caminho ausente e CRLF parecem idênticos -- ambos exibem cannot execute: required file not found sem mostrar o caminho. Em ambas as versões, não 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 binário real está 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, então o script funciona independente de o binário estar em /usr/bin ou /usr/local/bin. É a forma moderna e resiliente ao ambiente.

Note que passar argumentos para o interpretador através de env é limitado (sistemas mais antigos não suportam múltiplos argumentos). Opções como set -euo pipefail pertencem ao corpo do script, não ao shebang.

Como evitar que volte a acontecer?

Conclusão: Fixe arquivos .sh como LF com .gitattributes e configure seu editor para salvar como LF. Esses dois passos bloqueiam quase toda reintrodução de CRLF.

Corrigir uma vez é inútil se CRLF volta a cada save ou commit. Corte na origem.

Fixar terminações de linha no Git

Coloque um .gitattributes na raiz do repositório e fixe shell scripts como LF.

*.sh text eol=lf

Agora checkouts sempre usam LF, então o arquivo sobrevive a edições de máquinas Windows.

Verifique também sua configuração de core.autocrlf. No Linux/macOS, input é a escolha segura.

$ git config --global core.autocrlf input

core.autocrlf=true é comum entre desenvolvedores Windows, mas adiciona CRLF no checkout, criando condições 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: não use para shell scripts (tende a adicionar CRLF)

Checklist final

  1. file script.sh não 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 execução (x) ativo

Com os três em ordem, bad interpreter não retornará.

Próximas leituras