Fix '/bin/bash^M: bad interpreter: No such file or directory' โ€” CRLF Line Endings in Bash Scripts

beginner๐Ÿง Linux2026-03-23| Linux / macOS โ€” Bash scripts created or edited on Windows (Git Bash, WSL, VS Code, Notepad++)

Error Message

/bin/bash^M: bad interpreter: No such file or directory
#bash#crlf#line-ending#dos2unix#windows

The Error

You run a shell script and get this:

$ ./deploy.sh
-bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory

See that ^M? That's the smoking gun. Your script has Windows-style line endings (CRLF โ€” \r\n) instead of Unix-style (LF โ€” \n).

Because of those extra \r characters, Linux reads the shebang as #!/bin/bash\r and goes looking for a binary literally named /bin/bash^M. Spoiler: it doesn't exist.

Nine times out of ten, this happens when a script was written on Windows, edited in Notepad, or cloned from a repo where Git's core.autocrlf silently converted the line endings on checkout.

Confirm the Problem

Worth a quick sanity check before touching anything. Run:

file deploy.sh

A script with CRLF endings will say so explicitly:

deploy.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

Want to see the raw characters? cat -A makes them visible โ€” every line will have ^M right before the $:

cat -A deploy.sh | head -5
#!/bin/bash^M$
echo "Starting deploy..."^M$

That ^M$ pattern confirms it. Time to fix.

Fix It

Option 1: dos2unix (Fastest)

One command, done:

dos2unix deploy.sh

Got a whole directory of scripts? Convert them all at once:

dos2unix *.sh

Or recursively โ€” useful for projects with nested shell scripts:

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

Not installed? A one-liner fixes that too:

# Debian/Ubuntu
sudo apt install dos2unix

# RHEL/CentOS/Fedora
sudo yum install dos2unix

# macOS
brew install dos2unix

Option 2: sed (No Extra Tools Needed)

Already have sed? Strip the carriage returns directly:

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

macOS's sed is slightly different โ€” it needs an empty string after -i:

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

Option 3: tr

Classic Unix approach. Outputs to a temp file, then swaps it back:

tr -d '\r'  deploy_fixed.sh
mv deploy_fixed.sh deploy.sh
chmod +x deploy.sh

Option 4: vim

Already editing the file in vim? Fix it without leaving the editor:

:set ff=unix
:wq

Verify the Fix

Run file again. A clean script looks like this โ€” no mention of CRLF:

file deploy.sh
# deploy.sh: Bourne-Again shell script, ASCII text executable

Double-check with cat -A:

cat -A deploy.sh | head -5
#!/bin/bash$
echo "Starting deploy..."$

Lines ending with just $ โ€” no ^M. You're good. Run the script:

./deploy.sh

Prevent It From Happening Again

Git Configuration

The root cause is usually Git's core.autocrlf setting. On Windows, it converts LF โ†’ CRLF on checkout. Your colleagues check out the repo on Windows and unknowingly corrupt every shell script in it.

Lock it down at the repo level with a .gitattributes file:

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

Commit this once. From that point on, Git enforces LF endings for shell scripts no matter what OS anyone's using.

Alternatively, if you're working on Windows and want to stop Git from converting endings globally:

git config --global core.autocrlf input

This mode keeps LF on checkout and converts CRLF โ†’ LF on commit. It's the safer setting for cross-platform teams.

VS Code

Set LF as the default for new files in your workspace settings (.vscode/settings.json):

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

VS Code also shows the current file's line ending in the status bar โ€” bottom right corner, it'll say CRLF or LF. Click it to toggle instantly.

EditorConfig

Drop a .editorconfig in your repo root. Most modern editors pick it up automatically:

[*.sh]
end_of_line = lf

Combined with .gitattributes, this covers both the editing and the committing side.

Quick Reference

  • Fastest fix: dos2unix yourscript.sh
  • No extra tools: sed -i 's/\r//' yourscript.sh
  • Root cause: Windows line endings (\r\n) polluting the shebang line
  • Long-term fix: .gitattributes with *.sh text eol=lf

Related Error Notes