Quick fix
# One-liner: strip trailing CR
sed -i 's/\r$//' setup.sh && bash setup.sh
What you will run into
Running a script written on Windows inside WSL/Linux reports setup.sh: line 2: $'true\r': command not found, or bash: ./setup.sh: /bin/bash^M: bad interpreter.
The \r / ^M in the error is an invisible newline leftover - scripts saved with Notepad or Windows editors carry it.
Some scripts "partially run, then a few lines suddenly command not found" - exactly those commands whose line endings carry CR.
Why this happens
Windows text files end lines with CRLF (\r\n), Linux only uses LF (\n):
- CR after the command name: bash treats
true\ras one whole command name ->$'true\r': command not found(CR inside echo arguments usually doesn't error, so it's "flaky"); - CR in the shebang line:
#!/bin/bash\rmakes the kernel look for the/bin/bash\r(^M) interpreter ->bad interpreter.
Common sources: Notepad saves, Windows editors defaulting to CRLF, misconfigured git checkout (core.autocrlf).
A trailing CR ( , 0x0D) is an ordinary character in Linux text processing, not a line separator: when bash parses a script line, the whole line (including the trailing ) becomes the command name, and true ≠ true, hence $'true ': command not found.
Shebangs are parsed by the kernel: it reads the first line to find the interpreter path, and #!/bin/bash makes it look for a file named /bin/bash (which does not exist) → bad interpreter.
The two failures happen at different layers: command-name errors at the shell layer (command not found), shebang errors at the kernel exec layer (bad interpreter).
Deterministic takeaway: an error containing $'... ' or ^M means CRLF contamination — sed -i 's/ $//' or dos2unix cleans it in one shot;
if it reappears after git checkout, it is the line-ending policy (core.autocrlf/.gitattributes — see git-crlf); fix the repo config instead of editing files one by one;
fixed diagnostic: file <script> shows CRLF, cat -A shows ^M$.
Step by step
1. Confirm it's CRLF — Required
file setup.sh
Output containing with CRLF -> that's it (or cat -A setup.sh to see whether line endings end with ^M$).
2. Strip the CR — Required
sed -i 's/\r$//' setup.sh
Or dos2unix setup.sh (install it first with sudo apt install dos2unix if missing).
3. Only the shebang line is broken — Required
bash setup.sh invoking the interpreter explicitly bypasses shebang parsing (but body CR remains); the root fix is still stripping CR.
4. Prevention — Required
- Edit scripts inside Linux (vi/nano);
- Choose LF/Unix line endings in Windows editors (VS Code: bottom-right switch);
- Unify the
core.autocrlfpolicy in git repos; - After copying a script, run
file setup.shfirst.
How to confirm it works
bash setup.sh
No more command not found / bad interpreter = success. Measured: after sed -i 's/\r$//', the script works, exit=0; before the fix, body CR reported $'true\r': command not found (exit=127) and shebang CR reported bad interpreter (exit=126).
Other environments
| Environment | Notes |
|---|---|
| Running in WSL/Linux | Always strip CR: sed -i 's/\r$//' or dos2unix |
| Saved by a Windows editor | Notepad defaults to CRLF; VS Code bottom-right switch to LF |
| git checkout | Misconfigured core.autocrlf re-introduces CRLF |
| Some commands error | Exactly the commands whose line endings carry CR; strip CR across the whole file |
Symptom
Running a script written on Windows inside WSL/Linux reports two typical error classes:
$ bash setup.sh
setup.sh: line 2: $'true\r': command not found
$ ./setup.sh
bash: ./setup.sh: /bin/bash^M: bad interpreter: No such file or directory
- The
\r(or^M) in the error is an invisible newline leftover - scripts saved with Notepad/Windows editors carry it. - Some scripts look like they "partially run", then a few lines suddenly
command not found- exactly those commands whose line endings carry CR.
Cause
- Windows text files end lines with CRLF (\r\n), Linux only uses LF (\n).
- CR after the command name: bash treats
true\ras one whole command name ->$'true\r': command not found(CR inside echo arguments usually doesn't error, so it's "flaky"). - CR in the shebang line:
#!/bin/bash\rmakes the kernel look for the/bin/bash\r(^M) interpreter ->bad interpreter. - Common sources: Notepad saves, Windows editors defaulting to CRLF, misconfigured git checkout (
core.autocrlfrelated, see the git-crlf entry).
Solution
- Quick fix (convert line endings):
sed -i 's/\r$//' setup.sh
# or dos2unix setup.sh
- If only the shebang line is broken:
bash setup.shinvoking the interpreter explicitly bypasses shebang parsing (but body CR remains); the root fix is still stripping CR. - Prevention: edit scripts inside Linux (vi/nano); choose LF/Unix line endings in Windows editors; unify the
core.autocrlfpolicy in git repos (complementary to the git-crlf entry); after copying a script runfile setup.shfirst (showingwith CRLFmeans hit).
Verification Evidence
- This machine (WSL Ubuntu 6.18.35.2, bash 5.3.9, 2026-08-29):
- Measurement 1 (body CR):
printf '#!/bin/bash\ntrue\r\n'+bash->line 2: $'true\r': command not found, exit=127 - verbatim match with the user report. - Measurement 2 (shebang CR):
#!/bin/bash\r+chmod +x+./execution ->/bin/bash^M: bad interpreter: No such file or directory, exit=126. - Measurement 3 (fix): after
sed -i 's/\r$//', the script works, exit=0. - dos2unix not installed (example command honestly given, not measured).
Evidence details kept locally (2026-08-29)
Applicable tools (1)
This problem is linked from the tool pages below — reachable from either side.
bashSource & evidence
Source: https://stackoverflow.com/questions/2920416/configure-bin-shm-bad-interpreter
← Coding Agents & Terminal domain | Problem Catalog Experience | Facing another issue? Go to the Helpdesk