Fix "/bin/bash^M: bad interpreter: No such file or directory"
The script was saved with Windows line endings (CRLF). Strip the carriage returns and run it again:
sed -i 's/\r$//' script.sh
./script.sh
Or install dos2unix and run dos2unix script.sh. Then stop Git or your editor from adding them back (see "How to prevent it").
What the error means
You tried to run a script and got:
$ ./deploy.sh
-bash: ./deploy.sh: /bin/bash^M: bad interpreter: No such file or directory
The first line of the script, the shebang (#!/bin/bash), tells the kernel which program should run the file. Windows editors end every line with two bytes, carriage return plus line feed (\r\n). Linux treats only \n as the end of a line, so the kernel looks for an interpreter literally named /bin/bash\r. That file does not exist, hence "No such file or directory". The ^M is the terminal's way of printing the invisible carriage return.
The same problem shows up with other wording depending on how the script starts:
/usr/bin/env: 'bash\r': No such file or directory
/usr/bin/env: 'python3\r': No such file or directory
-bash: ./run.py: /usr/bin/python3^M: bad interpreter: No such file or directory
deploy.sh: line 2: $'\r': command not found
deploy.sh: line 7: syntax error near unexpected token `$'do\r''
The last two appear when you run bash deploy.sh directly: bash ignores the shebang but then trips over the carriage return at the end of every other line.
Confirm the cause
Two quick checks tell you whether the file has CRLF endings:
file deploy.sh
head -1 deploy.sh | od -c
Example output:
deploy.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
0000000 # ! / b i n / b a s h \r \n
"with CRLF line terminators" or a \r before \n confirms it. If neither appears, skip to cause 3 below. cat -A deploy.sh also works: CRLF lines end in ^M$ instead of $.
Cause 1: the file was edited or created on Windows (most common)
Notepad, many Windows IDEs, files copied from email or chat, and archives created on Windows all produce CRLF endings. Convert the file in place. Each of these does the same job; pick one:
# sed, available everywhere
sed -i 's/\r$//' deploy.sh
# dos2unix, purpose-built and also removes a UTF-8 BOM
dos2unix deploy.sh
# convert every .sh file below the current directory
find . -name '*.sh' -exec sed -i 's/\r$//' {} +
The sed expression deletes a \r only when it is the last character of a line, so it does not touch carriage returns inside the text. Install dos2unix with your package manager if you prefer it:
| Distro | Command |
|---|---|
| Ubuntu, Debian, Mint | sudo apt install dos2unix |
| Fedora | sudo dnf install dos2unix |
| Arch | sudo pacman -S dos2unix |
| openSUSE | sudo zypper install dos2unix |
In Vim you can convert the open file with :set ff=unix followed by :w. In VS Code, click "CRLF" in the status bar and choose "LF", then save.
Cause 2: Git converted the line endings on checkout
If the repository is fine on Linux machines but broken in your copy, Git is converting LF to CRLF. This happens when you clone on Windows with core.autocrlf=true and then use the files from Linux, WSL, a Docker build context or a shared folder in a VM. A Docker image built from such a checkout fails with exec /entrypoint.sh: no such file or directory for the same reason.
Fix it for the repository rather than per machine, by adding a .gitattributes file:
# .gitattributes
*.sh text eol=lf
*.py text eol=lf
Dockerfile text eol=lf
Then renormalize the working tree so existing files are rewritten:
git add --renormalize .
git status
git commit -m "Enforce LF line endings for scripts"
On a Windows machine that only edits Linux scripts, git config --global core.autocrlf input makes Git commit LF and never convert to CRLF on checkout.
Cause 3: the interpreter path really does not exist
If the file has normal LF endings, the message is literal: the program named on the shebang line is not installed or lives elsewhere. Look at the first line and check the path:
head -1 deploy.sh
command -v bash zsh python3 python
Common examples:
#!/usr/bin/pythonon a system that only haspython3. Change the shebang to#!/usr/bin/env python3, or on Ubuntu/Debian installpython-is-python3.#!/bin/zshor#!/usr/bin/fishwhen that shell is not installed. Install it or rewrite the shebang.- A hard-coded path like
#!/usr/local/bin/bashcopied from macOS or FreeBSD. Use#!/usr/bin/env bash, which finds bash onPATH. - A UTF-8 byte order mark before
#!.od -cshows357 273 277as the first bytes.dos2unixremoves it, or usesed -i '1s/^\xEF\xBB\xBF//' deploy.sh.
If the file is a compiled program rather than a script and you get "No such file or directory" even though it exists, the missing piece is its dynamic loader or a library; see "error while loading shared libraries" and "Exec format error".
Distro-specific notes
- All distros behave the same here: the kernel parses the shebang, so there is no distro setting that tolerates CRLF.
- Debian, Ubuntu and Mint link
/bin/shtodash, not bash. A script with#!/bin/shthat uses bash features fails with errors like[[: not found; that is a different problem from line endings. Use#!/bin/bashif you need bash syntax. - Fedora, Arch and openSUSE link
/bin/shto bash. All current distros have merged/usr, so/bin/bashand/usr/bin/bashare the same file. - WSL users hit this constantly when files live on the Windows side (
/mnt/c/...). Keep projects inside the Linux file system, or enforce LF with.gitattributes.
How to prevent it
- Commit a
.gitattributeswitheol=lffor scripts in every repository that ships shell or Python scripts. - Set your editor to LF for these file types. In VS Code:
"files.eol": "\n". An.editorconfigwithend_of_line = lfworks across most editors. - Add a check to CI:
grep -rlI $'\r' --include='*.sh' .prints any script that still contains carriage returns. - Use
#!/usr/bin/env bashfor portable scripts. The bash scripting guide covers shebangs and making scripts executable; if the error changes to "Permission denied", see fixing bash: Permission denied.
Still not working?
Show every non-printing character in the first lines so nothing hides from you:
head -3 deploy.sh | cat -A
ls -l deploy.sh
stat -c '%a %U' deploy.sh
If the first line now ends in $ with no ^M, the interpreter path exists and the file is executable, try running it with the interpreter explicitly (bash -x deploy.sh) to trace where it fails. The sed cheat sheet has more in-place editing recipes.
Frequently asked questions
What does ^M mean in a Linux error message?
^M is how the terminal shows a carriage return character (\r, byte 0x0D). Windows ends lines with CR+LF; Linux expects only LF, so the CR becomes part of the interpreter name.
How do I convert a file from CRLF to LF without dos2unix?
Run sed -i 's/\r$//' file.sh. It deletes a carriage return at the end of every line, in place.
Why does bash script.sh work but ./script.sh fails?
./script.sh makes the kernel read the shebang line, which contains the stray carriage return. bash script.sh skips the shebang, but the script can still fail later with $'\r': command not found, so fix the line endings anyway.
How do I stop Git from adding CRLF line endings?
Add *.sh text eol=lf to a .gitattributes file in the repository and commit it. On Windows also set git config --global core.autocrlf input or false.
Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.