I had seen this line #!/usr/bin/env node
at the beginning of some examples in nodejs
and I had googled without finding any topic that could answer
Scripts that are to be executed by an interpreter normally have a shebang line at the top to tell the OS how to execute them.
If you have a script named foo
whose first line is #!/bin/sh
, the system will read that first line and execute the equivalent of /bin/sh foo
. Because of this, most interpreters are set up to accept the name of a script file as a command-line argument.
The interpreter name following the #!
has to be a full path; the OS won't search your $PATH
to find the interpreter.
If you have a script to be executed by node
, the obvious way to write the first line is:
#!/usr/bin/node
but that doesn't work if the node
command isn't installed in /usr/bin
.
A common workaround is to use the env
command (which wasn't really intended for this purpose):
#!/usr/bin/env node
If your script is called foo
, the OS will do the equivalent of
/usr/bin/env node foo
The env
command executes another command whose name is given on its command line, passing any following arguments to that command. The reason it's used here is that env
will search $PATH
for the command. So if node
is installed in /usr/local/bin/node
, and you have /usr/local/bin
in your $PATH
, the env
command will invoke /usr/local/bin/node foo
.
The main purpose of the env
command is to execute another command with a modified environment, adding or removing specified environment variables before running the command. But with no additional arguments, it just executes the command with an unchanged environment, which is all you need in this case.
There are some drawbacks to this approach. Most modern Unix-like systems have /usr/bin/env
, but I worked on older systems where the env
command was installed in a different directory. There might be limitations on additional arguments you can pass using this mechanism. If the user doesn't have the directory containing the node
command in $PATH
, or has some different command called node
, then it could invoke the wrong command or not work at all.
Other approaches are:
#!
line that specifies the full path to the node
command itself, updating the script as needed for different systems; ornode
command with your script as an argument.See also this question (and my answer) for more discussion of the #!/usr/bin/env
trick.
Incidentally, on my system (Linux Mint 17.2), it's installed as /usr/bin/nodejs
. According to my notes, it changed from /usr/bin/node
to /usr/bin/nodejs
between Ubuntu 12.04 and 12.10. The #!/usr/bin/env
trick won't help with that (unless you set up a symlink or something similar).
UPDATE: A comment by mtraceur says (reformatted):
A workaround for the nodejs vs node problem is to start the file with the following six lines:
#!/bin/sh - ':' /*- test1=$(nodejs --version 2>&1) && exec nodejs "$0" "$@" test2=$(node --version 2>&1) && exec node "$0" "$@" exec printf '%s\n' "$test1" "$test2" 1>&2 */
This will first try
nodejs
and then trynode
, and only print the error messages if both of them are not found. An explanation is out of scope of these comments, I'm just leaving it here in case it helps anyone deal with the problem since this answer brought the problem up.
I haven't used NodeJS lately. My hope is that the nodejs
vs. node
issue has been resolved in the years since I first posted this answer. On Ubuntu 18.04, the nodejs
package installs /usr/bin/nodejs
as a symlink to /usr/bin/node
. On some earlier OS (Ubuntu or Linux Mint, I'm not sure which), there was a nodejs-legacy
package that provided node
as a symlink to nodejs
. No guarantee that I have all the details right.
Short answer: It is the path to the interpreter.
EDIT (Long Answer): The reason there is no slash before "node" is because you can not always guarantee the reliability of #!/bin/ . The "/env" bit makes the program more cross-platform by running the script in a modified environment and more reliably being able to find the interpreter program.
You do not necessarily need it, but it is good to use to ensure portability (and professionalism)
#!/usr/bin/env node
is an instance of a shebang line: the very first line in an executable plain-text file on Unix-like platforms that tells the system what interpreter to pass that file to for execution, via the command line following the magic #!
prefix (called shebang).
Note: Windows does not support shebang lines, so they're effectively ignored there; on Windows it is solely a given file's filename extension that determines what executable will interpret it. However, you still need them in the context of npm
.[1]
The following, general discussion of shebang lines is limited to Unix-like platforms:
In the following discussion I'll assume that the file containing source code for execution by Node.js is simply named file
.
You NEED this line, if you want to invoke a Node.js source file directly, as an executable in its own right - this assumes that the file has been marked as executable with a command such as chmod +x ./file
, which then allows you to invoke the file with, for instance, ./file
, or, if it's located in one of the directories listed in the $PATH
variable, simply as file
.
npm
based on the value of the "bin" key in a package's package.json file; also see this answer for how that works with globally installed packages. Footnote [1] shows how this is handled on Windows.You do NOT need this line to invoke a file explicitly via the node
interpreter, e.g., node ./file
Optional background information:
#!/usr/bin/env <executableName>
is a way of portably specifying an interpreter: in a nutshell, it says: execute <executableName>
wherever you (first) find it among the directories listed in the $PATH
variable (and implicitly pass it the path to the file at hand).
This accounts for the fact that a given interpreter may be installed in different locations across platforms, which is definitely the case with node
, the Node.js binary.
By contrast, the location of the env
utility itself can be relied upon to be in the same location across platforms, namely /usr/bin/env
- and specifying the full path to an executable is required in a shebang line.
Note that POSIX utility env
is being repurposed here to locate by filename and execute an executable in the $PATH
.
The true purpose of env
is to manage the environment for a command - see env's POSIX spec and Keith Thompson's helpful answer.
It's also worth noting that Node.js is making a syntax exception for shebang lines, given that they're not valid JavaScript code (#
is not a comment character in JavaScript, unlike in POSIX-like shells and other interpreters).
[1] In the interest of cross-platform consistency, npm
creates wrapper *.cmd
files (batch files) on Windows when installing executables specified in a package's package.json
file (via the "bin"
property). Essentially, these wrapper batch files mimic Unix shebang functionality: they invoke the target file explicitly with the executable specified in the shebang line - thus, your scripts must include a shebang line even if you only ever intend to run them on Windows - see this answer of mine for details.
Since *.cmd
files can be invoked without the .cmd
extension, this makes for a seamless cross-platform experience: on both Windows and Unix you can effectively invoke an npm
-installed CLI by its original, extension-less name.