🔄 The dos2unix Command

Convert Text Files from DOS/Windows Format to Unix/Linux Format

dos2unix [OPTIONS] [FILE...]

Overview

The dos2unix command is an essential utility for converting text files between DOS/Windows and Unix/Linux line ending formats. This seemingly simple task is critical because different operating systems use different control characters to mark the end of a line, and these differences can cause scripts to fail, programs to malfunction, and data to be misinterpreted.

The Problem:

  • DOS/Windows: Uses CR+LF (Carriage Return + Line Feed: \r\n or 0x0D 0x0A)
  • Unix/Linux: Uses LF only (Line Feed: \n or 0x0A)
  • Old Mac: Used CR only (Carriage Return: \r or 0x0D) - rarely seen now

Why This Matters:

  • Shell scripts with DOS line endings won't execute (#!/bin/bash^M errors)
  • Configuration files may be parsed incorrectly
  • Programs reading line-by-line may include CR in the data
  • Git commits show every line as changed even when content is identical
  • Text processing tools may behave unexpectedly
Technical Background:

The difference comes from historical typewriter mechanics. A carriage return moved the print head back to the start, and a line feed advanced the paper. Teletype machines needed both operations. Unix simplified this to just line feed, while DOS/Windows kept both for compatibility. In hex dumps, you'll see DOS line endings as 0D 0A and Unix as just 0A. In vim or cat -A, DOS line endings appear as ^M at the end of each line.

Common Options

Option Description
-k Keep file date stamp (don't update modification time)
-n New file mode (write to new file, keep original)
-o Write to original file (overwrite - default behavior)
-q Quiet mode (suppress warnings)
-v Verbose mode (show files being converted)
-b Make backup of original file (.bak extension)
-f Force conversion of binary files (use with caution!)
-c Specify conversion mode (ascii, 7bit, iso, mac)
-i Display file information (line endings, byte order mark, encoding)

Detailed Examples

Example 1

Basic File Conversion - Detecting the Problem

First, let's identify a file with DOS line endings and convert it.

# Check if file has DOS line endings using cat -A cat -A script.sh
#!/bin/bash^M$ ^M$ echo "Hello World"^M$ echo "This script has DOS line endings"^M$
Problem Identified: The ^M characters at the end of each line indicate carriage returns (CR). The $ shows the line feed (LF). This is the DOS/Windows format: CR+LF.
# Try to run the script - it will fail! ./script.sh
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
The Error: Bash is literally looking for a program called /bin/bash^M (with a carriage return in the name), which doesn't exist. The CR character is being treated as part of the interpreter path.
# Convert the file to Unix format dos2unix script.sh # Verify the conversion cat -A script.sh
dos2unix: converting file script.sh to Unix format... #!/bin/bash$ $ echo "Hello World"$ echo "This script has DOS line endings"$
Success! The ^M characters are gone. Now we only see $ at the end of lines (the LF character). The script will now execute properly.
# Now it works! ./script.sh
Hello World This script has DOS line endings
Real-World Scenario: This is the #1 issue when Windows users edit shell scripts in Notepad or other Windows editors and then upload them to Linux servers. The script looks fine but won't run.
Example 2

Converting Multiple Files at Once

Process multiple files in a single command, essential for batch operations.

# Convert multiple specific files dos2unix file1.txt file2.txt file3.sh config.conf # Convert all .sh files in current directory dos2unix *.sh # Convert all .txt files recursively find . -name "*.txt" -exec dos2unix {} \; # Convert all files in a directory dos2unix /path/to/scripts/*
dos2unix: converting file file1.txt to Unix format... dos2unix: converting file file2.txt to Unix format... dos2unix: converting file file3.sh to Unix format... dos2unix: converting file config.conf to Unix format...
Explanation: Dos2unix can accept multiple filenames as arguments, and it will process each one sequentially. You can use wildcards (*) to match multiple files, or combine it with find for recursive operations. This is invaluable when you've received a directory of files from Windows systems and need to convert them all.
Pro Tip: Before batch converting, use the -i option to check which files actually need conversion: dos2unix -i *.txt. This shows you which files have DOS line endings without modifying them.
Example 3

Creating Backups with -b Option

Always a good practice to keep the original file when you're not certain about the conversion.

# Convert file and create backup with .bak extension dos2unix -b important_config.conf # List files to see backup was created ls -lh important_config*
dos2unix: converting file important_config.conf to Unix format... -rw-r--r-- 1 craig users 2048 Jan 15 10:30 important_config.conf -rw-r--r-- 1 craig users 2052 Jan 15 10:25 important_config.conf.bak
Explanation: The -b option tells dos2unix to create a backup of the original file before converting it. The backup has a .bak extension. Notice the original file (now converted) is slightly smaller - those extra 4 bytes were the carriage return characters that were removed from 4 lines of text.
# Compare the files to see the difference diff important_config.conf.bak important_config.conf # Or use cmp to see the byte-level differences cmp -l important_config.conf.bak important_config.conf | head -5
1c1 < [database]^M --- > [database] 3c3 < host = localhost^M --- > host = localhost
Pro Tip: You can specify a custom backup suffix with -b: by default it uses .bak, but some versions allow custom suffixes in configuration.
Real-World Use: Essential when converting production configuration files or scripts. If something breaks after conversion, you have the original to revert to immediately.
Example 4

New File Mode with -n Option

Write the converted output to a new file while preserving the original unchanged.

# Convert and write to new file dos2unix -n windows_file.txt unix_file.txt # Verify both files exist ls -lh *_file.txt # Check line endings in both files file windows_file.txt unix_file.txt
dos2unix: converting file windows_file.txt to file unix_file.txt in Unix format... -rw-r--r-- 1 craig users 1024 Jan 15 10:20 windows_file.txt -rw-r--r-- 1 craig users 1020 Jan 15 10:35 unix_file.txt windows_file.txt: ASCII text, with CRLF line terminators unix_file.txt: ASCII text
Explanation: The -n option (new file mode) takes two arguments: the input file and the output file. The original file remains completely unchanged, and a new converted file is created. The file command confirms the line ending formats: "CRLF line terminators" for DOS format, and plain "ASCII text" for Unix format.
Batch New File Mode:
# Convert multiple files to new files with different extension for file in *.txt.dos; do dos2unix -n "$file" "${file%.dos}" done # This converts file1.txt.dos → file1.txt, file2.txt.dos → file2.txt, etc.
Real-World Use: Useful when you need to maintain both versions of a file, or when you're converting files that you don't have permission to modify but can create new files in the directory.
Example 5

Information Mode with -i Option

Check file information without converting - see what format files are in before making changes.

# Check file information dos2unix -i script1.sh script2.sh config.txt data.csv
6 0 0 no_bom text script1.sh 12 0 0 no_bom text script2.sh 8 8 0 no_bom text config.txt 150 150 0 no_bom text data.csv
Explanation: The output shows four columns:
  • Column 1: Number of Unix line endings (LF only)
  • Column 2: Number of DOS line endings (CR+LF)
  • Column 3: Number of Mac line endings (CR only)
  • Column 4: BOM status (Byte Order Mark)
  • Column 5: File type (text or binary)

In this example, script1.sh and script2.sh have only Unix line endings (already correct), config.txt has 8 DOS line endings (needs conversion), and data.csv has 150 DOS line endings (definitely needs conversion).

Pro Tip: Use this before doing batch conversions to identify which files actually need work. No point converting files that are already in the correct format!
# Check all files in directory and show only those needing conversion dos2unix -i *.txt | awk '$2 > 0 {print $6}'
config.txt readme.txt notes.txt
Smart Filtering: This command shows only files that have DOS line endings (column 2 greater than 0). Perfect for building a list of files that need conversion.
Example 6

Keeping File Timestamps with -k Option

Preserve the original modification time when converting files - important for build systems and version control.

# Check original timestamp ls -l --time-style=full-iso oldfile.txt
-rw-r--r-- 1 craig users 2048 2024-12-20 15:30:45.123456789 -0500 oldfile.txt
# Convert WITHOUT -k (default behavior) dos2unix oldfile.txt ls -l --time-style=full-iso oldfile.txt
dos2unix: converting file oldfile.txt to Unix format... -rw-r--r-- 1 craig users 2044 2025-01-15 10:35:12.987654321 -0500 oldfile.txt
Timestamp Changed: The modification time was updated to the current time when we converted the file. This can be a problem for build systems, Makefiles, or version control systems that depend on file timestamps.
# Now convert WITH -k to preserve timestamp dos2unix -k anotherfile.txt # Check the timestamp ls -l --time-style=full-iso anotherfile.txt
dos2unix: converting file anotherfile.txt to Unix format... -rw-r--r-- 1 craig users 3072 2024-12-20 15:30:45.123456789 -0500 anotherfile.txt
Timestamp Preserved: With the -k option, the file's modification time remains unchanged. The file is converted, but it appears as if it hasn't been touched.
Real-World Use: Critical when converting files in source code repositories where timestamps matter for incremental builds, or when you need to maintain the original file dates for compliance or auditing purposes. Also important when running dos2unix as part of a Git pre-commit hook.
Example 7

Converting Files in a Script Pipeline

Integrate dos2unix into automated workflows and deployment scripts.

#!/bin/bash # Deployment script that ensures all scripts have Unix line endings DEPLOY_DIR="/opt/application/scripts" LOG_FILE="/var/log/deployment.log" echo "========================================" | tee -a "$LOG_FILE" echo "Deployment started: $(date)" | tee -a "$LOG_FILE" echo "========================================" | tee -a "$LOG_FILE" # Find all shell scripts and convert them echo "Converting shell scripts to Unix format..." | tee -a "$LOG_FILE" find "$DEPLOY_DIR" -type f -name "*.sh" | while read script; do # Check if conversion is needed DOSLINES=$(dos2unix -i "$script" | awk '{print $2}') if [ "$DOSLINES" -gt 0 ]; then echo " Converting: $script (found $DOSLINES DOS line endings)" | tee -a "$LOG_FILE" dos2unix -k -b "$script" 2>&1 | tee -a "$LOG_FILE" # Make executable if it has a shebang if head -1 "$script" | grep -q "^#!"; then chmod +x "$script" echo " Made executable: $script" | tee -a "$LOG_FILE" fi else echo " Skipping: $script (already Unix format)" | tee -a "$LOG_FILE" fi done echo "========================================" | tee -a "$LOG_FILE" echo "Deployment completed: $(date)" | tee -a "$LOG_FILE" echo "========================================" | tee -a "$LOG_FILE"
======================================== Deployment started: Tue Jan 15 10:35:45 EST 2025 ======================================== Converting shell scripts to Unix format... Converting: /opt/application/scripts/backup.sh (found 45 DOS line endings) dos2unix: converting file /opt/application/scripts/backup.sh to Unix format... Made executable: /opt/application/scripts/backup.sh Skipping: /opt/application/scripts/monitor.sh (already Unix format) Converting: /opt/application/scripts/deploy.sh (found 67 DOS line endings) dos2unix: converting file /opt/application/scripts/deploy.sh to Unix format... Made executable: /opt/application/scripts/deploy.sh ======================================== Deployment completed: Tue Jan 15 10:35:52 EST 2025 ========================================
Explanation: This script demonstrates a production-ready approach to ensuring all deployed scripts have correct line endings. It checks each file first, only converts files that need it, preserves timestamps with -k, creates backups with -b, and automatically makes scripts executable if they have a shebang line. All actions are logged for audit purposes.
Real-World Use: Deployment automation, CI/CD pipelines, and Git hooks commonly include dos2unix operations to prevent line ending issues from causing production problems.
Example 8

Handling Mixed Line Endings

Some files have both DOS and Unix line endings mixed together - a particularly troublesome situation.

# Check a file with mixed line endings dos2unix -i mixed_file.txt
25 15 0 no_bom text mixed_file.txt
Mixed Format Detected: This file has 25 Unix line endings (LF) and 15 DOS line endings (CR+LF). This typically happens when multiple people edit the same file using different tools, or when files are partially edited on Windows and partially on Linux.
# Look at the problematic sections with cat -A cat -A mixed_file.txt | head -20
# Configuration File$ $ [section1]^M$ key1 = value1$ key2 = value2^M$ $ [section2]$ key3 = value3^M$ key4 = value4$
Visual Inspection: You can see some lines ending with just $ (Unix) and others with ^M$ (DOS). This inconsistency can cause parsing problems in some applications.
# Convert to consistent Unix format dos2unix mixed_file.txt # Verify all line endings are now consistent dos2unix -i mixed_file.txt
dos2unix: converting file mixed_file.txt to Unix format... 40 0 0 no_bom text mixed_file.txt
Problem Solved: Now all 40 lines have Unix line endings. The file is consistent and won't cause any line-ending-related parsing issues.
Common Cause: Git with incorrect line ending settings (autocrlf) is a frequent cause of mixed line endings. Ensure your Git configuration is correct: git config --global core.autocrlf input on Linux/Mac.
Example 9

Verbose Mode and Quiet Mode

Control the output verbosity based on your needs - detailed feedback or silent operation.

# Verbose mode - detailed output dos2unix -v file1.txt file2.txt file3.txt
dos2unix: converting file file1.txt to Unix format... dos2unix: Binary symbol 0x00 found at line 0 dos2unix: Converted 15 out of 15 line breaks. dos2unix: converting file file2.txt to Unix format... dos2unix: Converted 23 out of 23 line breaks. dos2unix: converting file file3.txt to Unix format... dos2unix: Converted 45 out of 45 line breaks.
Verbose Output: The -v option provides detailed information about each conversion, including how many line breaks were converted and any warnings (like binary symbols detected).
# Quiet mode - suppress warnings dos2unix -q file1.txt file2.txt file3.txt # Silent operation - redirect all output dos2unix file1.txt 2>/dev/null
[No output displayed]
Quiet Mode: The -q option suppresses warning messages. This is useful in automated scripts where you don't want warnings cluttering your logs. The second example shows completely silent operation by redirecting stderr to /dev/null.
When to Use Each:
  • Verbose (-v): When troubleshooting or during initial testing
  • Normal (default): For regular interactive use
  • Quiet (-q): In cron jobs or automated scripts
  • Silent (redirect stderr): When you absolutely want no output
Exit Status Checking:
# Check if conversion succeeded dos2unix -q important.txt if [ $? -eq 0 ]; then echo "Conversion successful" else echo "Conversion failed!" >&2 exit 1 fi
Example 10

Complete Workflow: From Detection to Conversion

A comprehensive example showing best practices for safe file conversion in a production environment.

#!/bin/bash # Safe file conversion workflow with full error checking TARGET_DIR="/opt/configs" BACKUP_DIR="/opt/configs/backup_$(date +%Y%m%d_%H%M%S)" LOG_FILE="/var/log/dos2unix_conversion.log" # Function to log messages log_message() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE" } # Check if dos2unix is installed if ! command -v dos2unix &> /dev/null; then log_message "ERROR: dos2unix is not installed!" log_message "Install with: yum install dos2unix" exit 1 fi log_message "Starting line ending conversion process" log_message "Target directory: $TARGET_DIR" # Create backup directory mkdir -p "$BACKUP_DIR" log_message "Created backup directory: $BACKUP_DIR" # Find all text files and check their format log_message "Scanning for files with DOS line endings..." FILES_TO_CONVERT=() while IFS= read -r file; do # Get DOS line count INFO=$(dos2unix -i "$file") DOS_COUNT=$(echo "$INFO" | awk '{print $2}') if [ "$DOS_COUNT" -gt 0 ]; then FILES_TO_CONVERT+=("$file") log_message " Found: $file ($DOS_COUNT DOS line endings)" fi done < <(find "$TARGET_DIR" -type f \( -name "*.conf" -o -name "*.cfg" -o -name "*.sh" \)) # Report findings if [ ${#FILES_TO_CONVERT[@]} -eq 0 ]; then log_message "No files need conversion. All files already have Unix line endings." exit 0 fi log_message "Found ${#FILES_TO_CONVERT[@]} file(s) needing conversion" # Ask for confirmation in interactive mode if [ -t 0 ]; then echo "" read -p "Proceed with conversion? (yes/no): " CONFIRM if [ "$CONFIRM" != "yes" ]; then log_message "Conversion cancelled by user" exit 0 fi fi # Process each file log_message "Beginning conversion..." CONVERTED=0 FAILED=0 for file in "${FILES_TO_CONVERT[@]}"; do # Create backup cp -p "$file" "$BACKUP_DIR/" # Convert with timestamp preservation if dos2unix -k "$file" 2>&1 | tee -a "$LOG_FILE"; then log_message " ✓ Converted: $file" ((CONVERTED++)) # If it's a shell script, ensure it's executable if [[ "$file" == *.sh ]] && head -1 "$file" | grep -q "^#!"; then chmod +x "$file" log_message " Made executable: $file" fi else log_message " ✗ FAILED: $file" ((FAILED++)) # Restore from backup cp -p "$BACKUP_DIR/$(basename "$file")" "$file" log_message " Restored from backup" fi done # Final report log_message "=========================================" log_message "Conversion Summary:" log_message " Successfully converted: $CONVERTED" log_message " Failed: $FAILED" log_message " Backups stored in: $BACKUP_DIR" log_message "=========================================" # Clean up old backups (keep last 5) log_message "Cleaning up old backups..." OLD_BACKUPS=$(ls -dt /opt/configs/backup_* 2>/dev/null | tail -n +6) if [ -n "$OLD_BACKUPS" ]; then echo "$OLD_BACKUPS" | xargs rm -rf log_message "Removed old backups" fi log_message "Process completed successfully"
[2025-01-15 10:35:45] Starting line ending conversion process [2025-01-15 10:35:45] Target directory: /opt/configs [2025-01-15 10:35:45] Created backup directory: /opt/configs/backup_20250115_103545 [2025-01-15 10:35:45] Scanning for files with DOS line endings... [2025-01-15 10:35:45] Found: /opt/configs/database.conf (23 DOS line endings) [2025-01-15 10:35:45] Found: /opt/configs/web.conf (45 DOS line endings) [2025-01-15 10:35:45] Found: /opt/configs/startup.sh (67 DOS line endings) [2025-01-15 10:35:45] Found 3 file(s) needing conversion [2025-01-15 10:35:45] Beginning conversion... [2025-01-15 10:35:45] ✓ Converted: /opt/configs/database.conf [2025-01-15 10:35:45] ✓ Converted: /opt/configs/web.conf [2025-01-15 10:35:45] ✓ Converted: /opt/configs/startup.sh [2025-01-15 10:35:45] Made executable: /opt/configs/startup.sh [2025-01-15 10:35:45] ========================================= [2025-01-15 10:35:45] Conversion Summary: [2025-01-15 10:35:45] Successfully converted: 3 [2025-01-15 10:35:45] Failed: 0 [2025-01-15 10:35:45] Backups stored in: /opt/configs/backup_20250115_103545 [2025-01-15 10:35:45] ========================================= [2025-01-15 10:35:45] Cleaning up old backups... [2025-01-15 10:35:45] Removed old backups [2025-01-15 10:35:45] Process completed successfully
Production-Ready Solution: This comprehensive script demonstrates enterprise-level best practices:
  • Checks for dos2unix installation before proceeding
  • Scans and identifies files needing conversion
  • Creates timestamped backups of all files
  • Preserves file timestamps during conversion
  • Logs all operations with timestamps
  • Handles errors gracefully with automatic restoration
  • Makes shell scripts executable after conversion
  • Provides summary statistics
  • Manages backup retention (keeps last 5)
  • Interactive confirmation in terminal mode
Real-World Use: This type of script is used in production environments for maintaining configuration files, especially after receiving updates from Windows-based development teams or when integrating with Windows-centric tools.

Comparison: Line Ending Conversion Methods

Method Pros Cons Best For
dos2unix Purpose-built, safe, preserves timestamps, handles edge cases Requires installation (not always available) Production use, batch operations
sed 's/\r$//' Available everywhere, no installation needed Doesn't preserve timestamps, requires redirection Quick one-off fixes, minimal systems
tr -d '\r' Simple, available everywhere Removes ALL carriage returns (dangerous!), no backups Simple cases only, not recommended
vim (set ff=unix) Interactive, visual feedback Manual, one file at a time, not scriptable Single file editing during development
Git (autocrlf) Automatic, repository-wide Can cause mixed line endings, needs careful setup Source code in Git repositories

Additional Information

Binary File Warning:

Dos2unix will refuse to convert binary files by default because changing bytes in binary files will corrupt them. If you see "Binary symbol found" warnings, investigate the file. It might be:

  • Actually a binary file (don't convert!)
  • A text file with unusual characters (check with file command)
  • An encoded file (UTF-16, UTF-32, etc.) that needs different handling

Use -f to force conversion ONLY if you're absolutely certain it's safe.

Installation:
# Oracle Linux / RHEL / CentOS sudo yum install dos2unix # Debian / Ubuntu sudo apt-get install dos2unix # Verify installation dos2unix --version
Related Commands:
  • unix2dos: Converts Unix line endings to DOS (opposite direction)
  • mac2unix: Converts old Mac line endings to Unix
  • unix2mac: Converts Unix line endings to old Mac format
  • file: Identifies file type and line ending format
  • cat -A: Visualizes invisible characters including line endings
Alternative Methods (when dos2unix not available):
# Using sed (preserves file in place) sed -i 's/\r$//' filename.txt # Using sed (create new file) sed 's/\r$//' inputfile.txt > outputfile.txt # Using tr (dangerous - removes ALL \r) tr -d '\r' < inputfile.txt > outputfile.txt # Using perl perl -pi -e 's/\r\n/\n/g' filename.txt # Using vim/vi vim '+set ff=unix' '+wq' filename.txt
Common Scenarios:
  • Shell scripts failing: First thing to check when a script won't run
  • Configuration files: Parse errors often caused by line endings
  • CSV data imports: Extra carriage returns cause parsing issues
  • Git commits: Mixed line endings show as entire file changed
  • Cron jobs failing: Scripts edited on Windows won't execute
  • Docker builds: Windows-edited Dockerfiles fail
Git Configuration Best Practices:
# On Linux/Mac (recommended) git config --global core.autocrlf input # This setting: # - Converts CRLF to LF on commit # - Leaves LF unchanged on checkout # - Prevents Windows line endings from entering repository # Create .gitattributes file in repository root: echo "* text=auto" > .gitattributes echo "*.sh text eol=lf" >> .gitattributes echo "*.conf text eol=lf" >> .gitattributes
Prevention is Better Than Cure:
  • Configure editors to use Unix line endings (LF only)
  • Set up Git properly with autocrlf=input
  • Use .gitattributes to enforce line endings
  • Add dos2unix to deployment pipelines
  • Set up pre-commit hooks to catch DOS line endings
  • Educate team members about line ending differences

Quick Reference Card

Task Command
Convert single file dos2unix filename.txt
Convert with backup dos2unix -b filename.txt
Convert multiple files dos2unix file1.txt file2.txt file3.txt
Convert to new file dos2unix -n input.txt output.txt
Check file format dos2unix -i filename.txt
Preserve timestamp dos2unix -k filename.txt
Convert all .sh files dos2unix *.sh
Recursive conversion find . -name "*.txt" -exec dos2unix {} \;
Verbose output dos2unix -v filename.txt
Quiet mode dos2unix -q filename.txt