node.js “/usr/bin/env node”在节点文件的开头到底是做什么的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33509816/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 19:28:02  来源:igfitidea点击:

What exactly does "/usr/bin/env node" do at the beginning of node files?

node.jsshebang

提问by Gepser

I had seen this line #!/usr/bin/env nodeat the beginning of some examples in nodejsand I had googled without finding any topic that could answer the reason for that line.

#!/usr/bin/env node在一些示例的开头看到了这一行,nodejs我用谷歌搜索却没有找到任何可以回答该行原因的主题。

The nature of the words makes search it not that easy.

单词的性质使搜索变得不那么容易。

I'd read some javascriptand nodejsbooks recently and I didn't remember seeing it in any of them.

我读了一些javascriptnodejs书籍最近,我不记得看到它在任何人。

If you want an example, you could see the RabbitMQofficial tutorial, they have it in almost all of their examples, here is one of them:

如果你想要一个例子,你可以看RabbitMQ官方教程,他们几乎在所有的例子中都有,这里是其中之一:

#!/usr/bin/env node

var amqp = require('amqplib/callback_api');

amqp.connect('amqp://localhost', function(err, conn) {
  conn.createChannel(function(err, ch) {
    var ex = 'logs';
    var msg = process.argv.slice(2).join(' ') || 'Hello World!';

    ch.assertExchange(ex, 'fanout', {durable: false});
    ch.publish(ex, '', new Buffer(msg));
    console.log(" [x] Sent %s", msg);
  });

  setTimeout(function() { conn.close(); process.exit(0) }, 500);
});

Could someone explain me what is the meaning of this line?

有人能解释一下这行是什么意思吗?

What is the difference if I put or remove this line? In what cases do I need it?

如果我放置或删除此行,有什么区别?在什么情况下我需要它?

回答by mklement0

#!/usr/bin/env nodeis an instance of a shebang line: the very first line in an executable plain-text file on Unix-like platformsthat tells the system what interpreter to pass that file to for execution, via the command line following the magic #!prefix (called shebang).

#!/usr/bin/env nodeshebang 行的一个实例类 Unix 平台上的可执行纯文本文件中的第一行,它通过魔术#!前缀(称为shebang)后面的命令行告诉系统将该文件传递给哪个解释器来执行.

Note: Windowsdoes notsupport shebang lines, so they're effectively ignoredthere; on Windows it is solely a given file's filename extensionthat determines what executable will interpret it. However, you still need them in the context of npm.[1]

注:的Windows没有支持家当线,所以他们有效地忽略了那里。在 Windows 上,它只是一个给定文件的文件扩展名,它决定了哪个可执行文件将解释它。但是,在npm. [1]

The following, general discussion of shebang linesis limited to Unix-like platforms:

以下对 shebang 行的一般讨论仅限于类 Unix 平台:

In the following discussion I'll assume that the file containing source code for execution by Node.js is simply named file.

在下面的讨论中,我将假设包含由 Node.js 执行的源代码的文件被简单地命名为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 $PATHvariable, simply as file.

    • Specifically, you need a shebang line to create CLIsbased on Node.js source files as part of an npm package, with the CLI(s) to be installed by npmbased on the value of the "bin"key in a package's package.jsonfile; also see this answerfor how that works with globallyinstalled packages. Footnote [1] shows how this is handled on Windows.
  • You do NOT needthis line to invoke a file explicitly via the nodeinterpreter, e.g., node ./file

  • 需要此行,如果你要调用一个Node.js的源文件,直接,因为它本身就是一个可执行文件-这是假定该文件已被标记为可执行的命令,例如chmod +x ./file,然后可以让您调用文件例如,使用./file, 或者,如果它位于$PATH变量中列出的目录之一中,则简单地作为file.

    • 具体来说,您需要一个 shebang 行来创建基于 Node.js 源文件的CLI作为 npm包的一部分,npm根据"bin"package.json文件中键的值安装 CLI ;另请参阅此答案,了解如何与全局安装的软件包配合使用。脚注 [1] 显示了如何在 Windows 上进行处理。
  • 不需要这一行来通过node解释器显式调用文件,例如,node ./file



Optional background information:

可选的背景信息

#!/usr/bin/env <executableName>is a way of portablyspecifying an interpreter: in a nutshell, it says: execute <executableName>wherever you (first) find it among the directories listed in the $PATHvariable (and implicitly pass it the path to the file at hand).

#!/usr/bin/env <executableName>是一种可移植地指定解释器的方法:简而言之,它说:<executableName>在您(首先)在$PATH变量中列出的目录中找到它的任何地方执行(并将其隐式传递到手头文件的路径)。

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.

这说明了一个给定的解释器可能安装在跨平台的不同位置的事实node,Node.js 二进制文件绝对是这种情况。

By contrast, the location of the envutility itself can be relied upon to be in the samelocation across platforms, namely /usr/bin/env- and specifying the fullpath to an executable is requiredin a shebang line.

相比之下,env实用程序本身的位置可以依赖于跨平台位于同一位置,即/usr/bin/env- 并且需要在 shebang 行中指定可执行文件的完整路径。

Note that POSIX utility envis being repurposedhere to locate by filename and execute an executable in the $PATH.
The true purpose of envis to manage the environment for a command - see env's POSIX specand Keith Thompson's helpful answer.

需要注意的是POSIX工具env重新利用这里的文件名来查找,并在执行可执行文件$PATH
的真正目的env是管理命令的环境 - 请参阅envPOSIX 规范Keith Thompson 的有用回答



It's also worth noting that Node.js is making a syntax exceptionfor 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).

还值得注意的是,Node.js对 shebang 行进行了语法例外处理,因为它们不是有效的 JavaScript 代码(#在 JavaScript 中不是注释字符,与 POSIX 类 shell 和其他解释器不同)。



[1] In the interest of cross-platform consistency, npmcreates wrapper*.cmdfiles (batch files) on Windowswhen installing executables specified in a package's package.jsonfile (via the "bin"property). Essentially, these wrapper batch files mimicUnix 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 answerof mine for details.
Since *.cmdfiles can be invoked without the .cmdextension, 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.

[1] 为了跨平台一致性,在安装包文件中指定的可执行文件(通过属性)时,在 Windows 上npm创建包装*.cmd文件(批处理文件)。从本质上讲,这些包装器批处理文件模仿Unix shebang 功能:它们使用 shebang 行中指定的可执行文件显式调用目标文件- 因此,即使您只打算在 Windows 上运行脚本您的脚本也必须包含一个 shebang 行- 请参阅此答案我的详细信息。 由于文件可以在没有package.json"bin"
*.cmd.cmd扩展,这提供了无缝的跨平台体验:在 Windows 和 Unix 上,您可以npm通过其原始的、无扩展的名称有效地调用已安装的 CLI。

回答by Keith Thompson

Scripts that are to be executed by an interpreter normally have a shebang lineat the top to tell the OS how to execute them.

由解释器执行的脚本通常在顶部有一个shebang 行,告诉操作系统如何执行它们。

If you have a script named foowhose 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.

如果您有一个名为foo的脚本,其第一行是#!/bin/sh,系统将读取该第一行并执行/bin/sh foo. 因此,大多数解释器都设置为接受脚本文件的名称作为命令行参数。

The interpreter name following the #!has to be a full path; the OS won't search your $PATHto find the interpreter.

后面的解释器名称#!必须是完整路径;操作系统不会搜索您$PATH以找到解释器。

If you have a script to be executed by node, the obvious way to write the first line is:

如果您有一个脚本要由 执行node,那么编写第一行的显而易见的方法是:

#!/usr/bin/node

but that doesn't work if the nodecommand isn't installed in /usr/bin.

但如果该node命令未安装在/usr/bin.

A common workaround is to use the envcommand (which wasn't reallyintended for this purpose):

一个常见的解决方法是使用env命令(这并不是真正用于此目的):

#!/usr/bin/env node

If your script is called foo, the OS will do the equivalent of

如果您的脚本被调用foo,操作系统将执行相当于

/usr/bin/env node foo

The envcommand 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 envwill search $PATHfor the command. So if nodeis installed in /usr/local/bin/node, and you have /usr/local/binin your $PATH, the envcommand will invoke /usr/local/bin/node foo.

env命令执行另一个命令,其名称在其命令行中给出,并将任何以下参数传递给该命令。在这里使用它的原因是env将搜索$PATH命令。因此,如果node安装在/usr/local/bin/node并且您/usr/local/bin在您的 中$PATH,该env命令将调用/usr/local/bin/node foo.

The main purpose of the envcommand 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.

env命令的主要目的是使用修改后的环境执行另一个命令,在运行该命令之前添加或删除指定的环境变量。但是没有额外的参数,它只是在没有改变的环境下执行命令,这就是你在这种情况下所需要的。

There are some drawbacks to this approach. Most modern Unix-like systems have /usr/bin/env, but I worked on older systems where the envcommand was installed in a different directory. There might be limitations on additional arguments you can pass using this mechanism. If the user doesn'thave the directory containing the nodecommand in $PATH, or has some different command called node, then it could invoke the wrong command or not work at all.

这种方法有一些缺点。大多数现代类 Unix 系统都有/usr/bin/env,但我在旧系统上工作,其中env命令安装在不同的目录中。您可以使用此机制传递的其他参数可能存在限制。如果用户在 中没有包含node命令的目录$PATH,或者有一些名为 的不同命令node,那么它可能调用错误的命令或根本不起作用。

Other approaches are:

其他方法是:

  • Use a #!line that specifies the full path to the nodecommand itself, updating the script as needed for different systems; or
  • Invoke the nodecommand with your script as an argument.
  • 使用#!一行指定node命令本身的完整路径,根据不同系统的需要更新脚本;或者
  • node使用您的脚本作为参数调用命令。

See also this question(and my answer) for more discussion of the #!/usr/bin/envtrick.

有关该技巧的更多讨论,另请参阅此问题(和我的回答#!/usr/bin/env

Incidentally, on my system (Linux Mint 17.2), it's installed as /usr/bin/nodejs. According to my notes, it changed from /usr/bin/nodeto /usr/bin/nodejsbetween Ubuntu 12.04 and 12.10. The #!/usr/bin/envtrick won't help with that (unless you set up a symlink or something similar).

顺便说一句,在我的系统(Linux Mint 17.2)上,它安装为/usr/bin/nodejs. 根据我的笔记,它在 Ubuntu 12.04 和 12.10 之间从/usr/bin/node变为/usr/bin/nodejs。这个#!/usr/bin/env技巧对此无济于事(除非您设置了符号链接或类似的东西)。

UPDATE: A comment by mtraceur says (reformatted):

更新: mtraceur 的评论说(重新格式化):

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 "
#!/bin/sh -
':' /*-
test1=$(nodejs --version 2>&1) && exec nodejs "##代码##" "$@"
test2=$(node --version 2>&1) && exec node "##代码##" "$@"
exec printf '%s\n' "$test1" "$test2" 1>&2
*/
" "$@" test2=$(node --version 2>&1) && exec node "##代码##" "$@" exec printf '%s\n' "$test1" "$test2" 1>&2 */

This will first try nodejsand then try node, 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.

nodejs vs node 问题的解决方法是使用以下六行启动文件:

##代码##

这将首先 trynodejs然后 try node,如果两者都找不到,则仅打印错误消息。解释超出了这些评论的范围,我只是把它留在这里,以防它帮助任何人解决问题,因为这个答案提出了问题。

I haven't used NodeJS lately. My hope is that the nodejsvs. nodeissue has been resolved in the years since I first posted this answer. On Ubuntu 18.04, the nodejspackage installs /usr/bin/nodejsas a symlink to /usr/bin/node. On some earlier OS (Ubuntu or Linux Mint, I'm not sure which), there was a nodejs-legacypackage that provided nodeas a symlink to nodejs. No guarantee that I have all the details right.

我最近没有使用 NodeJS。我希望自从我第一次发布这个答案以来,nodejsvs.node问题已经解决了。在 Ubuntu 18.04 上,该nodejs/usr/bin/nodejs作为符号链接安装到/usr/bin/node. 在一些早期的操作系统(Ubuntu 或 Linux Mint,我不确定是哪个)上,有一个nodejs-legacynode作为nodejs. 不能保证我所有的细节都是正确的。

回答by Quantum

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.

编辑(长答案):“节点”之前没有斜线的原因是因为您不能总是保证 #!/bin/ 的可靠性。“/env”位通过在修改后的环境中运行脚本并更可靠地找到解释器程序,使程序更具跨平台性。

You do not necessarily need it, but it is good to use to ensure portability (and professionalism)

您不一定需要它,但使用它可以确保便携性(和专业性)