If a script copied from Windows looks normal but macOS reports a “bad interpreter” or behaves as if commands have an extra character, check for Windows CRLF line endings. macOS command-line tools expect LF. You can confirm the file type, convert a copy with tools already on macOS, then run the repaired script again.

Why line endings break a script on macOS

A line ending is a character (or pair of characters) marking the end of a text line. macOS command-line tools use LF (\n); Windows commonly uses CRLF (\r\n). With CRLF, the carriage return can remain attached to a line when a Unix command reads it. Apple documents that this extra character can cause unexpected behavior in command-line tools and scripts. Apple’s shell-scripting guide

Common clues include /bin/bash^M: bad interpreter, a command-not-found message that appears to include a trailing \r, or parsing that fails even though the visible script looks correct. These symptoms can have other causes; checking the file is a useful first step, not proof by itself.

Check the script’s line-ending format

Open Terminal, change to the folder containing the script, and inspect it with file. Quote the filename so spaces and shell metacharacters are treated literally:

cd "$HOME/Downloads"
file "my script.sh"

If the output says the file has CRLF line terminators, that supports the diagnosis. If it reports LF, line endings may not be the cause. The macOS file command’s description can vary, and mixed endings may not be summarized clearly, so use the error message and the script’s source context too. To inspect a specific line’s bytes, macOS also includes od; for example:

od -An -tx1 -c "my script.sh" | head

A 0d 0a sequence represents CRLF; 0a alone is LF. Don’t treat a carriage return elsewhere in the file as a line ending without checking its position.

Convert CRLF to LF without overwriting the original

Apple’s macOS guidance notes that dos2unix is not included with macOS and recommends using tr or sed instead. For a CRLF script, remove carriage-return characters into a separate file, keeping the original as a backup:

cp -p "my script.sh" "my script.sh.bak"
tr -d '\r' < "my script.sh" > "my script.lf.sh"
file "my script.lf.sh"

This is appropriate when the unwanted carriage returns are Windows line-ending characters. It removes every CR byte in the file, so avoid it if the file intentionally uses carriage returns as data. The separate output also avoids truncating the input: redirecting directly back into the same file can erase it before conversion finishes.

Review the new file before replacing anything. If the contents look right and file reports LF endings, try running it with its intended interpreter. For a Bash script, for example:

bash "my script.lf.sh"

Running it through bash does not require the executable permission bit or a working shebang. If you need to run it directly as ./my script.lf.sh, make it executable and ensure its first line names an available interpreter, such as #!/bin/bash:

chmod +x "my script.lf.sh"
"./my script.lf.sh"

Once you have checked the repaired file, you can replace the original in Finder or Terminal. Keep the .bak copy until the script works as intended. If the script is part of a shared project, make the same line-ending correction in its source editor or repository workflow so the problem does not return when the file is saved again.

If the error remains

If file showed LF already, or conversion did not fix the failure, read the exact error and check the interpreter named on the first line. A missing interpreter, invalid path, syntax error, or lack of execute permission can produce similar failures. The script may also depend on commands or shell features unavailable in the interpreter it specifies.

TextEdit can open and save plain-text documents, but Apple’s documented TextEdit guide does not describe a line-ending selector. For this repair, use the Terminal conversion above or a code editor that explicitly shows and lets you change line endings; verify the saved file afterward. Apple’s TextEdit guide

The useful sequence is: identify the file’s format, preserve a backup, convert only when CRLF is present, and rerun using the intended interpreter. That keeps the fix specific to the file instead of changing unrelated scripts.

Sources