CRLF versus LF O Erro de Final de Linha que Quebra o CI
Seu script de shell funciona localmente, mas falha no CI com um erro de interpretador confuso. A causa é geralmente os caracteres de fim de linha CRLF. Aprenda o que são, por que quebram os pipelines do Linux e como resolver o problema permanentemente com .gitattributes e configurações de editor.
Seu script de shell funcionou bem no seu notebook. Você o empurra para o GitHub, o CI o detecta e a pipeline morre com um erro obscuro — algo como /bin/bash^M: bad interpreter ou uma tarefa que sai com código 126 por razões evidentes. O script é sintaticamente correto. Você não alterou nenhuma linha. Mas a build está quebrada.
Nove vezes de cada dez, o culpado é um final de linha. Especificamente, terminações de linha do Windows (CRLF) escondidas dentro de um arquivo que o Linux espera encontrar apenas com LF. Este artigo explica o que esses dois caracteres realmente são, por que a diferença importa mais do que a maioria dos desenvolvedores percebe e como eliminar o problema para sempre.
O que CRLF e LF Significam Na Realidade
Todo arquivo de texto precisa de uma forma de marcar o fim de uma linha. Dois caracteres de controle são usados em diferentes sistemas operacionais:
- LF (Feed de linha,
\n, hexa0x0A) — o padrão do Unix e do Linux. O macOS o usou desde a versão OS X. Um byte por cada final de linha. - CRLF (Retorno de carro + Feed de linha,
\r\n, hexa0x0D 0x0A) — o padrão do Windows, herdado do DOS, que o herdou das máquinas de teletipo. Dois bytes por cada final de linha.
Os nomes vêm das ações físicas de uma máquina de escrever antiga: um retorno de carro movia a cabeça de impressão para o início da linha; um feed de linha girava o papel uma linha. O DOS codificou literalmente ambas as ações. O Unix optou pelo método mais simples e manteve apenas o feed de linha.
Por que a CI quebra e seu notebook não quebra
Se você escreve código no Windows e seu editor salva arquivos com CRLF, tudo funciona localmente — as ferramentas do Windows lidam com os dois formatos de forma transparente. Mas sua pipeline de CI provavelmente roda no Linux, e os interpretadores de shell do Linux tratam \r como um caractere imprimível, não como espaço em branco. Quando o bash lê uma linha de script com final de linha em \r\n, ele vê o comando mais um retorno de carro no final. O resultado é assim:
/bin/bash^M: bad interpreter: No such file or directory
O ^M no erro é como terminais renderizam \r. O bash está tentando executar uma linha de shebang que termina com um retorno de carro, e, é claro, não existe um interpretador nesse caminho.
O mesmo problema aparece de formas mais sutis:
- Valores de variáveis de ambiente com terminações em
\rque quebram silenciosamente comparações de strings. - Scripts Docker
ENTRYPOINTfalhando ao iniciar porque a linha de shebang está corrompida. - Scripts do Python lendo arquivos de configuração e obtendo chaves como
"setting\r"em vez de"setting". - Makefiles ignorando regras porque o caractere de tab é seguido por
\r.
Como Detectar o Problema
Antes de corrigir qualquer coisa, confirme que o arquivo realmente tem terminações CRLF. Algumas formas rápidas:
cat -A (Linux/macOS)
cat -A deploy.sh
As linhas terminadas com CRLF mostrarão ^M$ no final. As linhas terminadas com LF mostrarão apenas $.
comando file
file deploy.sh
# deploy.sh: Bash script, ASCII text, with CRLF line terminators
xxd ou hexdump
xxd deploy.sh | grep "0d 0a"
Qualquer correspondência confirma CRLF. Se você vê apenas 0a nas terminações de linha, você está limpo.
Como Corrigir
dos2unix (a correção mais rápida)
Instale uma vez, execute em qualquer arquivo:
# Install
sudo apt install dos2unix # Debian/Ubuntu
brew install dos2unix # macOS
# Convert a single file
dos2unix deploy.sh
# Convert all shell scripts in the repo
find . -name "*.sh" -exec dos2unix {} \;
sed (sem ferramentas extras necessárias)
sed -i "s/\r//" deploy.sh
tr (seguro para POSIX)
tr -d "\r" < deploy.sh > deploy_fixed.sh && mv deploy_fixed.sh deploy.sh
Como Prevenir: Configuração do Git
Corrigir arquivos após o fato é reativo. A solução duradoura é dizer ao Git como lidar com terminações de linha, para que o problema nunca chegue ao seu repositório.
O método .gitattributes (recomendado)
A .gitattributes O arquivo commitado ao repositório garante terminações de linha consistentes para todos, independentemente das configurações locais dos desenvolvedores. Adicione isso na raiz do seu repositório:
# Normalize all text files to LF in the repo
* text=auto eol=lf
# Explicitly enforce LF for files that must never have CRLF
*.sh text eol=lf
*.bash text eol=lf
Makefile text eol=lf
Dockerfile text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.json text eol=lf
# Binary files — do not touch
*.png binary
*.jpg binary
*.gif binary
*.zip binary
*.gz binary
O text=auto eol=lf linha informa ao Git para detectar arquivos de texto automaticamente e armazená-los com LF, independentemente do sistema operacional do desenvolvedor. As linhas explícitas abaixo restringem arquivos onde CRLF causaria falhas em tempo de execução.
Após adicionar ou modificar .gitattributes, renormalize os arquivos existentes no repositório:
git add --renormalize .
git commit -m "normalize line endings"
A configuração core.autocrlf (apenas local)
O Git tem uma configuração global chamada core.autocrlf que controla a conversão de terminações de linha em checkout e commit. Os valores recomendados dependem do seu sistema operacional:
# Windows — convert CRLF to LF on commit, LF to CRLF on checkout
git config --global core.autocrlf true
# Linux/macOS — convert CRLF to LF on commit, no conversion on checkout
git config --global core.autocrlf input
O problema de depender apenas de core.autocrlf : ele se aplica apenas à máquina onde é configurado. Um contribuidor que nunca configurou isso ainda pode empurrar arquivos com CRLF. Um .gitattributes é enforcado pelo repositório em si, portanto é estritamente mais confiável.
Configurações do Editor para Serem Corretas
Seu editor é a primeira linha de defesa. Algumas configurações rápidas:
VS Code
O final de linha do arquivo atual é exibido na barra de status (canto inferior direito). Clique nele para alternar entre CRLF e LF. Para definir o padrão para novos arquivos, adicione isso ao seu settings.json:
{
"files.eol": "\n"
}
IDEs da JetBrains (IntelliJ, WebStorm, PyCharm)
Acesse Configurações → Editor → Estilo de Código e defina Separador de linha para Unix e macOS (\n). Você também pode adicionar um .editorconfig arquivo na raiz do repositório:
[*]
end_of_line = lf
insert_final_newline = true
A maioria dos editores modernos respeita .editorconfig naturalmente ou por meio de um plugin. Commitar esse arquivo ao repositório significa que os contribuidores recebem padrões consistentes sem configuração manual.
A Lista Completa de Verificação
Se você está padronizando um repositório que já teve problemas com terminações de linha, siga esta sequência:
- Adicione uma
.gitattributesarquivo com* text=auto eol=lfe regras explícitas para scripts de shell, Dockerfiles e arquivos de configuração. - Adicione um
.editorconfigarquivo comend_of_line = lf. - Execute
git add --renormalize . && git commit -m "normalize line endings"para corrigir arquivos já rastreados. - Execute
dos2unixem qualquer script não rastreado que será executado no Linux. - Conjunto
core.autocrlf inputglobalmente em máquinas Linux/macOS;trueem Windows. - Adicione um passo de verificação no CI — algo como
grep -rUl $'\r' *.sh— para capturar quaisquer regressões antes que cheguem a uma implantação.
Instale nossas extensões
Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida
恵 O placar chegou!
Placar é uma forma divertida de acompanhar seus jogos, todos os dados são armazenados em seu navegador. Mais recursos serão lançados em breve!
Ferramentas essenciais
Ver tudo Novas chegadas
Ver tudoAtualizar: Nosso ferramenta mais recente foi adicionado em 10 de junho de 2026
