How to Convert Line Endings Between CRLF and LF in Batch Script
If you work in a cross-platform environment (e.g., using Windows, Linux, and Mac), you have likely encountered issues with "Line Endings." Windows uses CRLF (Carriage Return + Line Feed), while Linux uses LF (Line Feed). If you try to run a script on Linux that has Windows line endings, it will fail with "bad interpreter" or "command not found" errors caused by the invisible \r character.
In this guide, we will demonstrate how to sanitize your text files by converting between these two standards using Batch and PowerShell.
The Problem: The Invisible Characters
- CRLF (
\r\n): Standard for Windows files. Two bytes:0x0D 0x0A. - LF (
\n): Standard for Unix/Linux/macOS files. One byte:0x0A.
When you view these in a standard text editor, they look identical. However, to a compiler or a server, they are completely different.
Method 1: Converting CRLF to LF (Windows to Unix)
The most reliable way to strip the Carriage Return (\r) in a Windows environment is to use PowerShell's [IO.File] methods from within your Batch script. These methods read and write raw bytes, preserving full control over line endings.
Implementation Script
@echo off
setlocal
set "Source=WindowsScript.sh"
set "Dest=LinuxScript.sh"
:: Verify source file exists
if not exist "%Source%" (
echo [ERROR] Source file "%Source%" not found.
pause
exit /b 1
)
echo Converting "%Source%" from CRLF to LF...
:: ReadAllText reads the file as a single string preserving line endings
:: Replace swaps CRLF byte pairs with LF only
:: WriteAllText writes the result as UTF-8 without BOM
powershell -NoProfile -Command "$text = [IO.File]::ReadAllText('%Source%'); $text = $text.Replace(\"`r`n\", \"`n\"); [IO.File]::WriteAllText('%Dest%', $text)"
if %errorlevel% equ 0 (
echo [SUCCESS] Converted to LF. Saved to "%Dest%".
) else (
echo [ERROR] Conversion failed.
pause
exit /b 1
)
pause
exit /b 0
The [IO.File]::ReadAllText() and [IO.File]::WriteAllText() methods operate on the file content as a single string, preserving full control over which bytes are written. Unlike Get-Content and Set-Content, they do not silently add or strip line endings during read/write operations.
Method 2: Converting LF to CRLF (Unix to Windows)
When moving files from a Linux system to Windows, you may need to add the Carriage Return character back. The replacement is performed in two steps: first normalize any existing CRLF to LF to avoid double conversion, then convert all LF to CRLF.
Implementation Script
@echo off
setlocal
set "Source=unix_config.conf"
set "Dest=windows_config.conf"
:: Verify source file exists
if not exist "%Source%" (
echo [ERROR] Source file "%Source%" not found.
pause
exit /b 1
)
echo Converting "%Source%" from LF to CRLF...
:: First normalize any existing CRLF to LF to prevent double conversion
:: Then convert all LF to CRLF
powershell -NoProfile -Command "$text = [IO.File]::ReadAllText('%Source%'); $text = $text.Replace(\"`r`n\", \"`n\").Replace(\"`n\", \"`r`n\"); [IO.File]::WriteAllText('%Dest%', $text)"
if %errorlevel% equ 0 (
echo [SUCCESS] Converted to CRLF. Saved to "%Dest%".
) else (
echo [ERROR] Conversion failed.
pause
exit /b 1
)
pause
exit /b 0
The two-step replacement (normalize to LF, then convert to CRLF) is critical. If you only run .Replace("n", "rn")on a file that already contains CRLF sequences, each\r\nbecomes\r\r\n`, corrupting the file with double Carriage Returns. Always normalize first.
Method 3: Verifying Line Ending Format
Before converting, it is useful to detect which line endings a file currently uses. This prevents unnecessary conversions and helps verify that a conversion completed successfully.
Implementation Script
@echo off
setlocal
set "Source=script.sh"
:: Verify source file exists
if not exist "%Source%" (
echo [ERROR] Source file "%Source%" not found.
pause
exit /b 1
)
echo Checking line endings in "%Source%"...
:: Read raw content and check for CRLF, bare LF, or mixed
powershell -NoProfile -Command "$text = [IO.File]::ReadAllText('%Source%'); $hasCRLF = $text.Contains(\"`r`n\"); $hasLF = $text.Replace(\"`r`n\", '').Contains(\"`n\"); if ($hasCRLF -and $hasLF) { 'Result: Mixed (CRLF and LF)' } elseif ($hasCRLF) { 'Result: CRLF (Windows)' } elseif ($hasLF) { 'Result: LF (Unix/macOS)' } else { 'Result: No line endings detected (single line or empty)' }"
pause
exit /b 0
The detection script checks for mixed line endings by first testing for CRLF, then stripping all CRLF sequences and checking whether bare LF characters remain. A "Mixed" result indicates the file was edited on both Windows and Unix systems without consistent normalization, this is the most common source of cross-platform line ending bugs.
Why Line Ending Conversion Matters
- Git Conflicts: If different team members use different line endings, Git will mark every single line as "Changed," leading to massive merge conflicts.
- Web Server Configs: Many web servers (like Nginx or Apache) will fail to start if their configuration files contain the wrong line endings for the host OS.
- Shell Scripts: A Bash script (
.sh) will not execute on a Linux box if it has\r\nline endings. The shell interprets the trailing\ras part of the command name, producing errors like/bin/bash^M: bad interpreter.
Best Practices
- Detect Before Converting: Use Method 3 to verify the current format before running a conversion. Converting a file that already has the correct line endings wastes time and risks corruption if the script has a bug.
- Verify Source File: Always check that the input file exists before processing. A missing source file will cause PowerShell to throw an exception that may not be clearly visible in the Batch output.
- Encoding Awareness: The
[IO.File]::WriteAllText(path, content)overload writes UTF-8 without a BOM by default. If your source file uses a different encoding (such as Windows-1252 or UTF-16), you may need to specify the encoding explicitly to prevent character corruption. - Configure Git: Use a
.gitattributesfile or thecore.autocrlfGit setting to enforce consistent line endings across your team. This prevents the problem at the source rather than fixing it after the fact. - Path Limitations: If your file paths contain single quotes (
'), the PowerShell commands above will break because the paths are wrapped in single quotes. Rename the file or use escaped quoting for such edge cases. - Preserve Original: Always write to a separate output file rather than overwriting the source. Verify the result before replacing the original.
Conclusion
Converting line endings is a critical sanitization step for any developer or sysadmin working in mixed-OS environments. By automating the transition from CRLF to LF or vice versa, you eliminate hidden bugs and execution failures that would otherwise be nearly impossible to see. These scripts ensure your data is compatible with any target system while giving you the tools to verify the result.