CRLF vs LF El error de finalización de línea que rompe el CI
Tu script de shell funciona localmente pero falla en el entorno CI con un error de intérprete confuso. La causa suele ser los saltos de línea CRLF. Aprende qué son, por qué rompen las pipelines de Linux y cómo solucionarlo permanentemente con .gitattributes y configuraciones de editores.
Tu script de shell funcionó bien en tu portátil. Lo subes a GitHub, el CI lo detecta y el pipeline muere con un error confuso — algo como /bin/bash^M: bad interpreter o una tarea que termina con código 126 por razones obvias. El script es sintácticamente correcto. No has modificado ninguna línea. Pero la compilación está rota.
Nueve veces de cada diez, el culpable es un salto de línea. Específicamente, salto de línea en formato Windows (CRLF) oculto dentro de un archivo que Linux espera encontrar solo con LF. Este artículo explica qué son esas dos letras, por qué la diferencia importa más de lo que muchos desarrolladores creen y cómo eliminar el problema para siempre.
Qué significan realmente CRLF y LF
Cada archivo de texto necesita una forma de marcar el final de una línea. Dos caracteres de control se usan en diferentes sistemas operativos:
- LF (Salto de línea,
\n, hex0x0A) — el estándar de Unix y Linux. macOS lo ha usado desde OS X. Un byte por salto de línea. - CRLF (Salto de carro + salto de línea,
\r\n, hex0x0D 0x0A) — el estándar de Windows, heredado de DOS, que a su vez lo heredó de máquinas de teletipo. Dos bytes por salto de línea.
Los nombres provienen de las acciones físicas de una antigua máquina de escribir: un salto de carro movía la cabeza de impresión al inicio de la línea; un salto de línea giraba el papel una línea. DOS codificó ambas acciones literalmente. Unix eligió el enfoque mínimo y conservó solo el salto de línea.
Por qué CI falla y tu portátil no
Si escribes código en Windows y tu editor guarda los archivos con CRLF, todo funciona localmente — las herramientas de Windows manejan ambos formatos de forma transparente. Pero tu pipeline de CI casi seguramente corre en Linux, y los interpretadores de shell de Linux tratan \r como un carácter imprimible, no como espacio en blanco. Cuando bash lee una línea de un script que termina en \r\n, ve el comando más un salto de carro al final. El resultado es este:
/bin/bash^M: bad interpreter: No such file or directory
El ^M en ese error es cómo los terminales renderizan \r. Bash está tratando de ejecutar una línea de shebang que termina con un salto de carro, y, por supuesto, no existe ningún intérprete en esa ruta.
El mismo problema aparece de formas más sutiles:
- Valores de variables de entorno con caracteres de salto de carro al final que rompen silenciosamente comparaciones de cadenas.
\rScripts de Docker que no arrancan porque la línea de shebang está corrupta. - Scripts de Python que leen archivos de configuración y obtienen claves como
ENTRYPOINTMakefiles ignoran reglas porque el carácter de tab está seguido por - Cómo detectar el problema
"setting\r"en lugar de"setting". - Antes de arreglar cualquier cosa, confirma que el archivo realmente tenga salto de línea CRLF. Algunas formas rápidas:
\r.
cat -A (Linux/macOS)
Las líneas que terminan en CRLF mostrarán
al final. Las líneas que terminan en LF solo mostrarán
cat -A deploy.sh
file command ^M$ xxd o hexdump $.
Cualquier coincidencia confirma CRLF. Si ves solo
file deploy.sh
# deploy.sh: Bash script, ASCII text, with CRLF line terminators
al final de las líneas, estás limpio.
xxd deploy.sh | grep "0d 0a"
Cómo arreglarlo 0a dos2unix (la solución más rápida)
Instálalo una vez, ejecútalo en cualquier archivo:
sed (sin necesidad de herramientas adicionales)
tr (seguro para POSIX)
# 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 {} \;
Cómo prevenirlo: configuración de Git
sed -i "s/\r//" deploy.sh
Arreglar archivos después de que ocurra el problema es reactiva. La solución duradera es indicar a Git cómo manejar los salto de línea para que el problema nunca llegue a tu repositorio.
tr -d "\r" < deploy.sh > deploy_fixed.sh && mv deploy_fixed.sh deploy.sh
El enfoque con .gitattributes (recomendado)
El archivo commitado al repositorio impone salto de línea consistentes para todos, independientemente de sus configuraciones locales. Añade esto en la raíz de tu repositorio:
line indica a Git que detecte automáticamente archivos de texto y los almacene con LF, independientemente del sistema operativo del desarrollador. Las líneas explícitas a continuación aseguran que los archivos con CRLF causen fallos en tiempo de ejecución.
A .gitattributes Después de añadir o modificar
# 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
El text=auto eol=lf , renormaliza los archivos existentes en el repositorio:
La configuración core.autocrlf (solo local) .gitattributesGit tiene una configuración global llamada
git add --renormalize .
git commit -m "normalize line endings"
que controla la conversión de salto de línea en el momento de la revisión y el commit. Los valores recomendados dependen de tu sistema operativo:
El problema de depender de core.autocrlf solo: se aplica solo en la máquina donde se establece. Un contribuyente que nunca la haya configurado aún puede empujar archivos con CRLF. Un
# 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
se enforces por el repositorio en sí, por lo que es mucho más confiable. core.autocrlf Configuraciones del editor para obtener bien .gitattributes Tu editor es la primera línea de defensa. Algunas configuraciones rápidas:
El salto de línea actual del archivo se muestra en la barra de estado (esquina inferior derecha). Haz clic en él para cambiar entre CRLF y LF. Para establecer el valor predeterminado para nuevos archivos, añade esto a tu
Editores JetBrains (IntelliJ, WebStorm, PyCharm)
(CLI)
Ve a settings.json:
{
"files.eol": "\n"
}
Configuración → Editor → Estilo de código
y establece Separador de líneas Unix y macOS (\n) . También puedes añadir un a archivo en la raíz del repositorio:La mayoría de los editores modernos lo respetan nativamente o mediante un complemento. Compartirlo en el repositorio significa que los contribuyentes obtienen valores predeterminados consistentes sin necesidad de configuración manual. .editorconfig La lista completa de verificación
[*]
end_of_line = lf
insert_final_newline = true
Si estás estandarizando un repositorio que ha tenido problemas con salto de línea, sigue este orden: .editorconfig archivo con
y reglas explícitas para scripts de shell, Dockerfiles y archivos de configuración.
Añade un
- Agrega una
.gitattributespara arreglar los archivos ya trazados.* text=auto eol=lfen cualquier script no trazado que se ejecute en Linux. - globalmente en máquinas Linux/macOS;
.editorconfigpara arreglar los archivos ya trazados.end_of_line = lf. - Ejecuta
git add --renormalize . && git commit -m "normalize line endings"en Windows. - Ejecuta
dos2unixAñade un paso de validación en CI — algo como - Conjunto
core.autocrlf input— para capturar cualquier regresión antes de que llegue a una implementación.trueen Windows. - Agregar un paso de revisión de CI — algo como
grep -rUl $'\r' *.sh— para detectar cualquier regresión antes de que llegue a una implementación.
Instalar extensiones
Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas
恵 ¡El marcador ha llegado!
Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!
Herramientas clave
Ver todo Los recién llegados
Ver todoActualizar: Nuestro última herramienta fue agregada el 11 de junio de 2026
