Error message
bad interpreter: No such file or directory
Windows line endings make the shebang point at an interpreter that does not exist.
Quick diagnosis
Start here. This one command usually tells you which of the causes below you are dealing with:
$ sed -i "s/\r$//" script.sh Strips the carriage returns in place. Then run the script again — that is usually the whole fix.
Causes, ordered by how often they are the culprit
1 Windows line endings (CRLF) — over 90% of cases
The file travelled through a Windows editor, a Git checkout with autocrlf enabled, or a shared folder.
$ file script.sh && head -1 script.sh | cat -A $ sed -i "s/\r$//" script.sh The giveaway: `file` says "with CRLF line terminators", or cat -A shows ^M$ at the end of lines. dos2unix script.sh does the same job if installed.
2 The interpreter genuinely is not installed
A script starting with #!/bin/zsh or #!/usr/bin/python fails on a machine without zsh, or where only python3 exists.
$ head -1 script.sh && ls -l /usr/bin/python* $ sudo apt install the-interpreter Prefer a portable shebang: #!/usr/bin/env python3 finds the interpreter through PATH instead of a fixed location.
3 The shebang path is wrong
Different distributions place interpreters differently, and a copied shebang may point at a path that only existed on the author's machine.
$ which bash python3 node $ #!/usr/bin/env bash 4 A space or a BOM before the shebang
The #! must be the very first two bytes of the file. A leading blank line, a space, or a UTF-8 byte order mark added by an editor breaks it.
$ head -c 20 script.sh | xxd | head -2 $ sed -i "1s/^\xEF\xBB\xBF//" script.sh If xxd shows efbbbf at the start, that is a BOM. Save the file as "UTF-8 without BOM" in your editor.
How to stop it happening again
- Configure your editor to save shell scripts with LF endings. In VS Code: the CRLF/LF indicator in the bottom-right corner switches it.
- Add a .gitattributes with `*.sh text eol=lf` so scripts keep Unix endings whatever the platform.
- On Windows, set git config --global core.autocrlf input rather than true.
- Use #!/usr/bin/env interpreter instead of hardcoded paths — it survives moving between distributions.
Frequently asked questions
The path in the error looks correct, so why does it fail?
Because there is an invisible \r at the end of it. The system is looking for "/bin/bash\r", not "/bin/bash". Confirm with head -1 script.sh | cat -A.
What is ^M in cat -A output?
A carriage return (CR, \r) — the Windows half of CRLF line endings. Its presence at the end of lines confirms this diagnosis.
How do I fix many files at once?
find . -name "*.sh" -exec sed -i "s/\r$//" {} + converts every script under the current directory.
Can I avoid the shebang entirely?
Yes, by invoking the interpreter directly: bash script.sh. It works, but the file stops being independently executable — the shebang exists for a reason.
Commands involved
Change file permissions with numeric (755, 644) and symbolic (u+x) modes — clearly explained.
sedStream-edit text: substitute, delete lines, and edit files in place with -i.
catPrint file contents, number lines, and join multiple files together.
which & typeWhich binary actually runs when you type a name — and unmask aliases.
Concepts behind this error: Shebang (#!) · PATH · Shell
How to do it properly
Other errors
SSH rejected your login because no key you offered was accepted by the server.
bash: command: command not foundThe shell searched every directory in your PATH and found no executable with that name.
No such file or directoryThe path you gave does not resolve — but often the missing part is not the one you think.
Permission deniedThe path resolves fine — the system simply will not let you do that with it.