“/ usr / bin / env节点”到底在节点文件的开始处做了什么?

我曾经在nodejs的一些例子的开头看过这行#!/usr/bin/env node ,并且我没有find可以回答该行的原因的任何主题。

单词的性质使得search不那么容易。

我最近读了一些javascriptnodejs书,我不记得在其中任何一本。

如果你想要一个例子,你可以看到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); }); 

有人能解释一下这条线的含义吗?

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

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

注意: Windows不支持shebang行 ,所以它们在那里被有效地忽略 ; 在Windows上,它只是一个给定文件的文件扩展名 ,它决定了可执行文件将解释它。 但是,你仍然需要在npm的情况下[1]

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

在下面的讨论中,我假定包含由Node.js执行的源代码的文件是简单的命名file

  • 需要这一行 ,如果你想直接调用一个Node.js源文件,作为一个可执行文件 – 它假设文件已经被标记为可执行文件,如chmod +x ./file ,然后允许你使用例如./file调用该文件,或者如果它位于$PATHvariables中列出的目录之一中,则简单地作为file

    • 具体来说,您需要一个shebang行来创build基于Node.js源文件的CLI作为npm 包的一部分,CLI将根据包的package.json "bin"键的值通过npm进行安装package.json文件 ; 也看到这个答案如何与全球安装的软件包一起工作。 脚注[1]显示了如何在Windows上处理这个问题。
  • 不需要通过node解释器显式调用文件,例如node ./file


可选的背景信息

#!/usr/bin/env <executableName>是一种可移植指定解释器的方法:简而言之,它说:execute <executableName>无论你在哪里(首先)在$PATHvariables列出的目录中find它把它传递给手头文件的path)。

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

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

请注意,POSIX实用程序env重新用于此处,以按文件名进行定位并在$PATH执行一个可执行文件。
env的真正目的是pipe理一个命令的环境 – 请参阅env的POSIX规范和Keith Thompson的有用答案 。


同样值得注意的是,Node.js为shebang行创build了一个语法exception ,因为它们不是有效的JavaScript代码( #不像JavaScript中的注释字符,不像POSIX类的shell和其他解释器)。


[1]为了实现跨平台一致性, npm在安装程序包的package.json文件中指定的可执行文件(通过"bin"属性)时在Windows上创buildwrapper *.cmd文件(batch file )。 实质上,这些包装batch file模仿 Unix shebangfunction:它们用shebang行中指定的可执行文件显式地调用目标文件 – 因此, 即使您只是打算在Windows上运行它们您的脚本也必须包含shebang行 – 请参阅此答案我的细节。
由于*.cmd文件可以在没有.cmd扩展名的情况下被调用,因此可以获得无缝的跨平台体验:在Windows和Unix上,您可以通过原始的扩展名来有效地调用npm installed CLI。

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

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

#!之后的解释器名称#! 必须是一个完整的path; 操作系统将不会search您的$PATHfind解释器。

如果你有一个脚本被node执行,写第一行的方法是:

 #!/usr/bin/node 

但是如果node命令没有安装在/usr/bin ,那不起作用。

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

 #!/usr/bin/env node 

如果您的脚本被称为foo ,则操作系统将执行相同的操作

 /usr/bin/env node foo 

env命令会执行另一个在其命令行上给出名称的命令,并将任何以下parameter passing给该命令。 这里使用的原因是env会search$PATH作为命令。 因此,如果node安装在/usr/local/bin/node ,并且在$PATH/usr/local/bin ,则env命令将调用/usr/local/bin/node foo

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

这种方法有一些缺点。 大多数现代类Unix系统都有/usr/bin/env ,但我曾经在较旧的系统上安装过env命令安装在不同的目录中。 使用这种机制可能会传递额外的参数。 如果用户在$PATH 中没有包含node命令的目录,或者有一些不同的命令叫做node ,那么它可能会调用错误的命令或者根本不工作。

其他方法是:

  • 使用#! 该行指定node命令本身的完整path,根据需要更新不同系统的脚本; 要么
  • 用脚本调用node命令作为参数。

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

顺便说一下,在我的系统(Linux Mint 17.2)上,它被安装为/usr/bin/nodejs 。 根据我的说明,它在Ubuntu 12.04和12.10之间从/usr/bin/node更改为/usr/bin/nodejs#!/usr/bin/env技巧对此没有帮助(除非你设置了一个符号链接或类似的东西)。

简短的回答:这是翻译的道路。

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

你不一定需要它,但是确保可移植性(和专业性)