-bash: ./deploy.sh: cannot execute: required file not found — the script is there,
but it was saved with Windows line endings. Its first line is #!/bin/bash plus a
carriage return, so Linux looks for an interpreter called bash\r, finds none, and
bash reports a missing file. Strip the carriage returns with sed -i 's/\r$//' deploy.sh
and the script runs.
Older answers quote the same failure as /bin/bash^M: bad interpreter: No such file or
directory. The bash 5.2.21 in Ubuntu 24.04 never printed that wording in this test, only
the line above. To keep the problem from coming back, add *.sh text eol=lf to the
repository's .gitattributes.
The error
$ ./deploy.sh
-bash: ./deploy.sh: cannot execute: required file not found
That is the wording of an interactive login shell (the prompt is shortened to $).
An interactive shell that is not a login shell starts the line with bash:, and
through bash -c './deploy.sh' it starts with bash: line 1: and the exit
code is 127. A script whose first line is #!/usr/bin/env bash fails with a
different message for the same reason:
/usr/bin/env: ‘bash\r’: No such file or directory
/usr/bin/env: use -[v]S to pass options in shebang lines
Why it happens
When Linux runs a file that starts with #!, the kernel takes the rest of the first
line as the path of the interpreter. A CRLF file keeps the carriage return on that line:
$ head -n 1 deploy.sh | od -c
0000000 # ! / b i n / b a s h \r \n
0000015
$ file deploy.sh
deploy.sh: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
There is no /bin/bash\r, the kernel reports "no such file", and bash 5.2 turns that
into "required file not found" next to the script's name. The carriage returns came from Windows
PowerShell 5.1: Set-Content wrote every line with CRLF. The same file ran without
complaint in Git Bash, which hides the problem until the script reaches Linux. Running it as
bash deploy.sh in WSL did not help either: the run finished, but
set -e failed with "invalid option", so the script ran without its safety net.
The fix
$ sed -i 's/\r$//' deploy.sh
$ file deploy.sh
deploy.sh: Bourne-Again shell script, ASCII text executable
$ ./deploy.sh
Deploying clinic-api to staging
Done
dos2unix deploy.sh does the same, but it was not installed in the WSL distribution;
Git Bash ships it (7.5.2), and it converted the same file on the Windows side. To fix the
repository rather than one copy, pin shell scripts to LF and renormalize:
$ cat .gitattributes
*.sh text eol=lf
$ git add --renormalize .
$ git add .gitattributes
$ git ls-files --eol deploy.sh
i/lf w/crlf attr/text eol=lf deploy.sh
i/lf means the repository now stores LF, but the working copy (w/crlf)
still had CRLF. After the commit, deleting the file and running
git checkout -- deploy.sh gave w/lf, and that copy ran in WSL. A fresh
clone made with core.autocrlf=true also received LF.
How it was reproduced
A four-line deploy.sh was written with Set-Content in Windows PowerShell
5.1, copied to /tmp/fix6-gitdocker in WSL (Ubuntu 24.04.4, bash 5.2.21, file 5.45)
and run three ways: from bash -c, from an interactive shell and from an interactive
login shell. The bash in the cached ubuntu:24.04, .NET 10 SDK and postgres:16 images is also 5.2,
so the older wording could not be tried without downloading an older distribution. The Git steps used Git for Windows 2.45.2 in Git Bash 5.2.26.
Frequently asked
- What does 'cannot execute: required file not found' mean in bash?
- The file you ran exists, but the program named on its first line does not. With a Windows CRLF script the interpreter name ends in a carriage return, and /bin/bash followed by that character cannot be found.
- How do I fix /bin/bash^M: bad interpreter?
- It is the same CRLF problem in older wording. Remove the carriage returns with sed -i 's/\r$//' script.sh or dos2unix, then run the script again. Add *.sh text eol=lf to .gitattributes so it stays fixed.
- Why does my shell script run in Git Bash but not in WSL?
- In this test Git Bash ran the CRLF script without complaint, while bash in WSL treated the carriage return as part of the interpreter name. Convert the script to LF once and it runs in both.
More decoded errors in the Fixes category. The same CRLF problem inside a container, where it surfaces as a missing entrypoint: exec /entrypoint.sh: no such file or directory.