Fix 'bad interpreter: No such file or directory' Error Caused by Windows CRLF Line Endings on macOS

beginner๐ŸŽ macOS2026-05-04| macOS (all versions), bash/zsh shell, shell scripts edited on Windows or cloned from repos with CRLF line endings

Error Message

bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
#bash#shell#crlf#macos

TL;DR

Your shell script has Windows-style line endings (CRLF) instead of Unix-style (LF). The ^M in the error is a carriage return character (\r) stuck to the end of /bin/bash, making the shebang unreadable. Fix it with:

sed -i '' 's/\r//' script.sh

Or with dos2unix if you have it:

dos2unix script.sh

Then run your script again.

What's Actually Happening

When you see this error:

bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory

That ^M is not some cryptic flag. It's a literal carriage return (\r, ASCII 13) sitting at the end of your shebang line. To macOS, the first line of your script looks like this:

#!/bin/bash\r\n

The kernel tries to find an interpreter at the path /bin/bash\r. That path doesn't exist. Script won't run.

Scripts pick up CRLF when created or edited on Windows โ€” Notepad, VS Code with its default CRLF setting, or WSL with misconfigured git โ€” and then land on macOS. Windows terminates lines with \r\n. Unix and macOS expect just \n.

Four common ways it gets in:

  • Cloning a repo where .gitattributes forces CRLF checkout
  • Copying a script from a Windows machine via USB or file share
  • Editing in VS Code with files.eol set to \r\n
  • Downloading a script from a site that stored it with CRLF

Verify the Problem First

Confirm CRLF is actually the issue before touching anything:

cat -A script.sh | head -5

Lines ending in ^M$ mean CRLF. A clean Unix file just shows $.

The file command gives you a plain-English answer:

file script.sh
# With CRLF: script.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
# Clean:     script.sh: Bourne-Again shell script, ASCII text executable

For a raw byte view, xxd shows exactly what's there:

xxd script.sh | head -3

CRLF shows up as 0d 0a pairs. Unix line endings are just 0a.

Fix Approaches

Option 1: sed (built into macOS, no install needed)

sed -i '' 's/\r//' script.sh

The -i '' syntax is macOS-specific โ€” GNU sed on Linux drops the empty string and uses just -i. This strips every \r in-place.

Option 2: dos2unix (the right tool for the job)

Install it first:

brew install dos2unix

Then convert:

dos2unix script.sh

Got a whole directory of shell scripts? One command handles all of them:

find . -name "*.sh" -exec dos2unix {} \;

Option 3: tr (another built-in option)

tr -d '\r'  script_fixed.sh
mv script_fixed.sh script.sh

tr can't edit files in-place, so you need the intermediate file dance.

Option 4: Fix it in VS Code before committing

Click CRLF in the bottom-right corner of VS Code and switch it to LF, then save. To make LF the permanent default for all new files, add this to your VS Code settings:

{
  "files.eol": "\n"
}

Option 5: Fix at the git level (prevent recurrence)

If CRLF keeps reappearing after every checkout, git is converting line endings behind the scenes. Stop it:

# For this repo only
git config core.autocrlf false

# Or globally
git config --global core.autocrlf input

The more durable fix is a .gitattributes file checked into the repo itself:

# .gitattributes
*.sh text eol=lf
*.bash text eol=lf

Commit this once, and every contributor โ€” Windows, macOS, Linux โ€” gets LF-only line endings on checkout. No per-machine config required.

Verify the Fix Worked

Run the same check as before:

file script.sh
# Should show: ASCII text executable (no CRLF mention)

Make the script executable and run it:

chmod +x script.sh
./script.sh

The /bin/bash^M: bad interpreter error is gone.

Quick Reference

  • Symptom: ^M in error message, script won't execute
  • Cause: CRLF line endings from Windows editors or misconfigured git
  • Fastest fix: sed -i '' 's/\r//' script.sh (no install needed)
  • Best long-term fix: .gitattributes with *.sh text eol=lf

Related Error Notes