Reputation: 6037
I am making an NW.js app on macOS, and want to run the app in dev mode by double-clicking on an icon. In the first step, I'm trying to make my shell script work.
Using VS Code on Windows (I wanted to gain time), I have created a run-nw
file at the root of my project, containing this:
#!/bin/bash
cd "src"
npm install
cd ..
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &
but I get this output:
$ sh ./run-nw
: command not found
: No such file or directory
: command not found
: No such file or directory
Usage: npm <command>
where <command> is one of: (snip commands list)
(snip npm help)
[email protected] /usr/local/lib/node_modules/npm
: command not found
: No such file or directory
: command not found
Some things I don't understand.
\r\n
with \n
(in case the \r
creates problems) but it changes nothing.dirname
instruction),
or maybe it doesn't know about the cd
command ?install
argument to npm
.npm install
manually)...Not able to make it work properly, and suspecting something weird with
the file itself, I created a new one directly on the Mac, using vim this time.
I entered the exact same instructions, and... now it works without any
issues.
A diff
on the two files reveals exactly zero difference.
What can be the difference? What can make the first script not work? How can I find out?
Following the accepted answer's recommendations, after the wrong line
endings came back, I checked multiple things.
It turns out that since I copied my ~/.gitconfig
from my Windows
machine, I had autocrlf=true
, so every time I modified the bash
file under Windows, it re-set the line endings to \r\n
.
So, in addition to running dos2unix
(which you will have to
install using Homebrew on a Mac), if you're using Git, check your
.gitconfig
file.
Upvotes: 116
Views: 76294
Reputation: 153
If you are getting an error saying
/usr/bin/env: ‘bash\r’: No such file or directory
It generally happens because the script you're invoking has embedded \r characters, which in turn suggests that it has Windows-style \r\n line endings (newlines) instead of the \n-only line endings bash expects
You need to "reset" the environment variables to ensure that you are using the default environment settings. This can be done by running the following command in your terminal:
source /etc/profile
source ~/.bashrc
source ~/.profile
You can run these commands by opening a terminal or, if you are using WSL, by connecting to your WSL instance to execute the commands.
Upvotes: 0
Reputation: 1873
Just in case if you (like me) need to have a script editable in Windows, but runnable in Linux (so the script MAY have CRLF, and we cannot have 2 versions, one for Linux, another for Windows), I came to the following way of running the script in Linux (./build.sh
is the script)
sed -e 's/\r$//' ./build.sh | bash
Upvotes: 0
Reputation: 4634
For IntelliJ users, here is the solution for writing Linux script: File > Line Separators
Use LF - Unix and macOS (\n)
Upvotes: 0
Reputation: 11578
For Notepad++ users, this can be solved by: Edit > EOL Conversion > Unix (LF)
Upvotes: 3
Reputation: 98861
In JetBrains products (PyCharm, PHPStorm, IDEA, etc.), you'll need to click on CRLF
/LF
to toggle between the two types of line separators (\r\n
and \n
).
Upvotes: 14
Reputation: 11983
Yes. Bash scripts are sensitive to line-endings, both in the script itself and in data it processes. They should have Unix-style line-endings, i.e., each line is terminated with a Line Feed character (decimal 10, hex 0A in ASCII).
With Windows or DOS-style line endings , each line is terminated with a Carriage Return followed by a Line Feed character. You can see this otherwise invisible character in the output of cat -v yourfile
:
$ cat -v yourfile
#!/bin/bash^M
^M
cd "src"^M
npm install^M
^M
cd ..^M
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M
In this case, the carriage return (^M
in caret notation or \r
in C escape notation) is not treated as whitespace. Bash interprets the first line after the shebang (consisting of a single carriage return character) as the name of a command/program to run.
^M
, it prints : command not found
src^M
, it prints : No such file or directory
install^M
instead of install
as an argument to npm
which causes npm
to complain.Like above, if you have an input file with carriage returns:
hello^M
world^M
then it will look completely normal in editors and when writing it to screen, but tools may produce strange results. For example, grep
will fail to find lines that are obviously there:
$ grep 'hello$' file.txt || grep -x "hello" file.txt
$
(no match because the line actually ends in ^M
)
Appended text will seem to overwrite the line because the carriage return moves the cursor to the start of the line:
$ sed -e 's/$/!/' file.txt
!ello
!orld
String comparison will fail, even though strings appear to be the same when writing to screen:
$ a="hello"; read b < file.txt
$ if [[ "$a" = "$b" ]]
then echo "Variables are equal."
else echo "Sorry, $a is not equal to $b"
fi
Sorry, hello is not equal to hello
The solution is to convert the file to use Unix-style line endings. There are a number of ways this can be accomplished:
Using the dos2unix
program:
dos2unix filename
Open the file in a capable text editor (Sublime, Notepad++, not Notepad) and configure it to save files with Unix line endings, e.g., with Vim, run the following command before (re)saving:
:set fileformat=unix
If you have a version of the sed
utility that supports the -i
or --in-place
option, e.g., GNU sed
, you could run the following command to strip trailing carriage returns:
sed -i 's/\r$//' filename
With other versions of sed
, you could use output redirection to write to a new file. Be sure to use a different filename for the redirection target (it can be renamed later).
sed 's/\r$//' filename > filename.unix
Similarly, the tr
translation filter can be used to delete unwanted characters from its input:
tr -d '\r' <filename >filename.unix
With the Bash port for Cygwin, there’s a custom igncr
option that can be set to ignore the Carriage Return in line endings (presumably because many of its users use native Windows programs to edit their text files).
This can be enabled for the current shell by running set -o igncr
.
Setting this option applies only to the current shell process so it can be useful when sourcing files with extraneous carriage returns. If you regularly encounter shell scripts with DOS line endings and want this option to be set permanently, you could set an environment variable called SHELLOPTS
(all capital letters) to include igncr
. This environment variable is used by Bash to set shell options when it starts (before reading any startup files).
The file
utility is useful for quickly seeing which line endings are used in a text file. Here’s what it prints for for each file type:
Bourne-Again shell script, ASCII text executable
Bourne-Again shell script, ASCII text executable, with CR line terminators
Bourne-Again shell script, ASCII text executable, with CRLF line terminators
The GNU version of the cat
utility has a -v, --show-nonprinting
option that displays non-printing characters.
The dos2unix
utility is specifically written for converting text files between Unix, Mac and DOS line endings.
Wikipedia has an excellent article covering the many different ways of marking the end of a line of text, the history of such encodings and how newlines are treated in different operating systems, programming languages and Internet protocols (e.g., FTP).
With Classic Mac OS (pre-OS X), each line was terminated with a Carriage Return (decimal 13, hex 0D in ASCII). If a script file was saved with such line endings, Bash would only see one long line like so:
#!/bin/bash^M^Mcd "src"^Mnpm install^M^Mcd ..^M./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M
Since this single long line begins with an octothorpe (#
), Bash treats the line (and the whole file) as a single comment.
Note: In 2001, Apple launched Mac OS X which was based on the BSD-derived NeXTSTEP operating system. As a result, OS X also uses Unix-style LF-only line endings and since then, text files terminated with a CR have become extremely rare. Nevertheless, I think it’s worthwhile to show how Bash would attempt to interpret such files.
Upvotes: 145
Reputation: 61
I was trying to startup my Docker container from Windows and got this:
Bash script and /bin/bash^M: bad interpreter: No such file or directory
I was using Git Bash and the problem was with the Git config, then I just did the steps below and it worked. It will configure Git to not convert line endings on checkout:
git config --global core.autocrlf input
Many thanks to Jason Harmon in this link: https://forums.docker.com/t/error-while-running-docker-code-in-powershell/34059/6
Before that, I tried this, that didn't work:
dos2unix scriptname.sh
sed -i -e 's/\r$//' scriptname.sh
sed -i -e 's/^M$//' scriptname.sh
Upvotes: 6
Reputation: 6076
Lots of reference to git but not to renormalizing the line endings in place. Just go to the root of your repo and run:
git add --renormalize .
Only the files that need line endings refreshed will be re-checked in. It will appear that the files have no changes, because line endings are invisible.
Upvotes: 3
Reputation: 151
I've had corrupted bash scripts so many times from this issue.
There are already many solutions posted on how to change the file. Though, I didn't see any on the built-in vim method to do this task.
Open vim with the shell script and run this command
:set ff=unix
Then edit your .gitattributes to get a permanent fix
Upvotes: 0
Reputation: 195
Scripts may call each other. An even better magic solution is to convert all scripts in the folder/subfolders:
find . -name "*.sh" -exec sed -i -e 's/\r$//' {} +
You can use dos2unix
too but many servers do not have it installed by default.
Upvotes: 0
Reputation: 11374
I ran into this issue when I use git with WSL.
git has a feature where it changes the line-ending of files according to the OS you are using, on Windows it make sure the line endings are \r\n
which is not compatible with Linux which uses only \n
.
You can resolve this problem by adding a file name .gitattributes
to your git root directory and add lines as following:
config/* text eol=lf
run.sh text eol=lf
In this example all files inside config
directory will have only line-feed line ending and run.sh
file as well.
Upvotes: 3
Reputation: 125708
If you're using the read
command to read from a file (or pipe) that is (or might be) in DOS/Windows format, you can take advantage of the fact that read
will trim whitespace from the beginning and ends of lines. If you tell it that carriage returns are whitespace (by adding them to the IFS
variable), it'll trim them from the ends of lines.
In bash (or zsh or ksh), that means you'd replace this standard idiom:
IFS= read -r somevar # This will not trim CR
with this:
IFS=$'\r' read -r somevar # This *will* trim CR
(Note: the -r
option isn't related to this, it's just usually a good idea to avoid mangling backslashes.)
If you're not using the IFS=
prefix (e.g. because you want to split the data into fields), then you'd replace this:
read -r field1 field2 ... # This will not trim CR
with this:
IFS=$' \t\n\r' read -r field1 field2 ... # This *will* trim CR
If you're using a shell that doesn't support the $'...'
quoting mode (e.g. dash, the default /bin/sh on some Linux distros), or your script even might be run with such a shell, then you need to get a little more complex:
cr="$(printf '\r')"
IFS="$cr" read -r somevar # Read trimming *only* CR
IFS="$IFS$cr" read -r field1 field2 ... # Read trimming CR and whitespace, and splitting fields
Note that normally, when you change IFS
, you should put it back to normal as soon as possible to avoid weird side effects; but in all these cases, it's a prefix to the read
command, so it only affects that one command and doesn't have to be reset afterward.
Upvotes: 5
Reputation: 131
Since VS Code is being used, we can see CRLF or LF in the bottom right depending on what's being used and if we click on it we can change between them (LF is being used in below example):
We can also use the "Change End of Line Sequence" command from the command pallet. Whatever's easier to remember since they're functionally the same.
Upvotes: 4
Reputation: 6387
For the sake of completeness, I'll point out another solution which can solve this problem permanently without the need to run dos2unix all the time:
sudo ln -s /bin/bash `printf 'bash\r'`
Upvotes: -1
Reputation: 494
If you are using a text editor like BBEdit you can do it at the status bar. There is a selection where you can switch.
Upvotes: 0
Reputation: 189307
Coming from a duplicate, if the problem is that you have files whose names contain ^M
at the end, you can rename them with
for f in *$'\r'; do
mv "$f" "${f%$'\r'}"
done
You properly want to fix whatever caused these files to have broken names in the first place (probably a script which created them should be dos2unix
ed and then rerun?) but sometimes this is not feasible.
The $'\r'
syntax is Bash-specific; if you have a different shell, maybe you need to use some other notation. Perhaps see also Difference between sh and bash
Upvotes: 3
Reputation: 1718
The simplest way on MAC / Linux - create a file using 'touch' command, open this file with VI or VIM editor, paste your code and save. This would automatically remove the windows characters.
Upvotes: 0
Reputation: 671
One more way to get rid of the unwanted CR ('\r') character is to run the tr
command, for example:
$ tr -d '\r' < dosScript.py > nixScript.py
Upvotes: 2