Skip to main content
DevOps Insightsguides & answers

Linux · troubleshooting

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

The kernel could not find the program named on the script's first line. The ^M in the message means the file has Windows line endings, so the interpreter's name ends in an invisible carriage return; otherwise the path itself is wrong. If you see ^M, strip the carriage returns (the sed command below); otherwise correct the path on the first line.

Reproduced on bash 3.2.57, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 8 sections

Before you start

  • A shell where the script fails, and the file itself.

Run this first

step 1 of 1
file script.sh; head -1 script.sh | od -c | head -2

Look for \r at the end of the first line, or a path that does not exist

Shows the line endings and the exact bytes of the shebang, including an invisible \r.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Does the message show ^M after the interpreter's name?

Cause space

2 of 2 still possible

  • The script has Windows (CRLF) line endingsCommon
  • The interpreter is not at that pathOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    file script.sh; head -1 script.sh | od -c | head -2

    Shows the line endings and the exact bytes of the shebang, including an invisible \r.

    Look for \r at the end of the first line, or a path that does not exist

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The script has Windows (CRLF) line endings

Common

Edited or created on Windows, checked out by Git with core.autocrlf converting to CRLF, or pasted from a Windows tool.

Confirm

file script.sh; head -1 script.sh | od -c | head -2

with CRLF line terminators, or \r before \n on the first line

Fix

  • Strip the carriage returns: sed -i 's/\r$//' script.sh on Linux, sed -i '' $'s/\r$//' script.sh on macOS, or dos2unix script.sh if it is installed.
  • Stop it recurring: add *.sh text eol=lf to .gitattributes and commit, so Git stores and checks out LF whatever each person's settings.
printf '*.sh text eol=lf\n' >> .gitattributes && git add .gitattributes && git add --renormalize -- '*.sh' && git commit -m 'Shell scripts use LF'

Reproduced on git 2.50.1: the repository then stores LF and a fresh clone runs. Limit --renormalize to the scripts: with . it also stages any other edited file. Once that commit is made, refresh your own copy with rm script.sh && git checkout -- script.sh; uncommitted edits to that file are lost.

The interpreter is not at that path

Occasional

The shebang names a program that is missing or lives elsewhere on this machine, such as /usr/bin/bash where bash is /bin/bash, or a Python version that is not installed.

Confirm

head -1 script.sh    # then: ls -l on the path it names

The path in the first line does not exist

Fix

  • Point it at a path that exists, or use #!/usr/bin/env bash so the program is found on PATH.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

The first line of a script, #!/bin/bash, tells the system which program runs it. A file saved on Windows ends each line with a carriage return as well as a newline. The system then looks for a program literally called bash followed by that invisible character, and there is none.

Words used on this page

Shebang
The #! first line naming the interpreter, such as #!/bin/bash or #!/usr/bin/env python3.
CRLF
Windows line endings: carriage return (shown as ^M or \r) then line feed. Linux and macOS use LF alone.
.gitattributes
A file telling Git how to treat files; *.sh text eol=lf makes it store and check out shell scripts with LF.
What is actually happening

Reproduced on macOS with a script saved with CRLF endings. bash 3.2.57 printed bash: ./run.sh: /bin/bash^M: bad interpreter: No such file or directory and exited 126; zsh printed its own wording with exit 127. file run.sh reported with CRLF line terminators.

Running bash run.sh hid the error but not the problem: every line still ended in a carriage return. echo printed hello followed by \r, and cd /tmp failed with cd: /tmp: No such file or directory, because the directory name really was /tmp plus a carriage return. The script carried on in the wrong directory and exited 0.

A shebang naming a program that does not exist, such as #!/usr/bin/python9, gives the same message without the ^M.

Inside a container the same problem usually surfaces differently, as exec ...: no such file or directory.

How to tell this is your problem
WhereWhat you see
bashbash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
zshzsh: ./script.sh: bad interpreter: /bin/bash^M: no such file or directory
file script.sh... with CRLF line terminators

How to know it is actually fixed

  • file reports no CRLF, and ./script.sh runs.

Stopping it happening again

  • Commit a .gitattributes with *.sh text eol=lf.
  • Set your editor to LF line endings for shell scripts.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it