“/ usr / bin / env节点”到底在节点文件的开始处做了什么?
我曾经在nodejs
的一些例子的开头看过这行#!/usr/bin/env node
,并且我没有find可以回答该行的原因的任何主题。
单词的性质使得search不那么容易。
我最近读了一些javascript
和nodejs
书,我不记得在其中任何一本。
如果你想要一个例子,你可以看到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 node
是shebang行的一个实例 : 类Unix平台上的可执行纯文本文件中的第一行,告诉系统通过命令传递该文件以执行的解释器线以下魔术#!
前缀(称为shebang )。
注意: Windows不支持shebang行 ,所以它们在那里被有效地忽略 ; 在Windows上,它只是一个给定文件的文件扩展名 ,它决定了可执行文件将解释它。 但是,你仍然需要在npm
的情况下 。 [1]
以下关于shebang行的一般性讨论仅限于Unix类平台:
在下面的讨论中,我假定包含由Node.js执行的源代码的文件是简单的命名file
。
-
你需要这一行 ,如果你想直接调用一个Node.js源文件,作为一个可执行文件 – 它假设文件已经被标记为可执行文件,如
chmod +x ./file
,然后允许你使用例如./file
调用该文件,或者如果它位于$PATH
variables中列出的目录之一中,则简单地作为file
。- 具体来说,您需要一个shebang行来创build基于Node.js源文件的CLI作为npm 包的一部分,CLI将根据包的
package.json
"bin"
键的值通过npm
进行安装package.json
文件 ; 也看到这个答案如何与全球安装的软件包一起工作。 脚注[1]显示了如何在Windows上处理这个问题。
- 具体来说,您需要一个shebang行来创build基于Node.js源文件的CLI作为npm 包的一部分,CLI将根据包的
-
您不需要通过
node
解释器显式调用文件,例如node ./file
可选的背景信息 :
#!/usr/bin/env <executableName>
是一种可移植指定解释器的方法:简而言之,它说:execute <executableName>
无论你在哪里(首先)在$PATH
variables列出的目录中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您的$PATH
find解释器。
如果你有一个脚本被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解释程序,使程序更具跨平台性。
你不一定需要它,但是确保可移植性(和专业性)