在终端上键入`node`时运行的代码

时间:2018-07-30 21:15:50

标签: c node.js bash terminal

我正在尝试了解shebang的工作原理,并想知道在终端提示符下键入node时会发生什么。想知道它是否在某个地方的c functions之一中调用main。我已经使用节点一段时间了,但我只了解基础知识。 shebang #!/usr/bin/env node以某种方式读取节点可执行文件,我不确定该文件是什么,在哪里,以及它从什么开始。然后是实际计算表达式node并将其定向到shebang的代码,但这可能太过复杂而无法询问。

1 个答案:

答案 0 :(得分:10)

确切地说,“ shebang”只是两个字符#!。当将Unix系统上的文件作为可执行文件调用(最终通过系统调用execve)时,内核会查看其前几个字节以确定可执行文件的种类。如果这些字节将其标识为包含机器代码,则内核会将机器代码加载到内存中,并使CPU开始执行它。如果机器代码是从C程序编译的,则其main函数将最终被调用。 (如果您想了解过程的工作原理,请阅读John Levine撰写的《链接器和加载器》一书。)

但是,如果前两个字节是#!(ASCII值35和33),则内核将扫描文件的第一行以查找解释器的名称< / em>,然后它将运行解释器,并提供#!程序的名称作为命令行参数。 (有关内核如何解析第一行的确切详细信息,请参见this answer。)

./foo.js a b c d

并且foo.js以#! /usr/bin/node开头,然后内核将表现为好像已使用参数vector调用了execve

/usr/bin/node ./foo.js a b c d

,它将打开文件/usr/bin/node,发现该文件是机器代码可执行文件,然后继续加载机器代码(即Node解释程序)并运行它。然后,Node的main函数将注意到其第一个参数为./foo.js,它将打开该文件并将其作为Javascript程序执行,而不是进入其交互式的read-evaluate-print循环。

Node解释器本身会忽略#!行,但是它必须在其解析器中包含代码才能忽略它。内核不会将其过滤掉。在Unix上常用的许多解释语言(sh,awk,perl,python,ruby等)中,注释从#到行尾,因此,此操作自动发生;实际上,之所以选择#!表示法,是因为 的注释是从#到行尾。 Javascript注释不能那样工作,因此Node必须在文件开头的#!有特殊情况。


您显示的#!行还有一个间接级别:#! /usr/bin/env node使内核运行带有参数vector的程序/usr/bin/env(同样由机器代码组成)

/usr/bin/env node ./foo.js a b c d

env然后看到它的第一个参数是node,它沿着搜索路径查找名为node的程序的可执行文件。搜索路径由环境变量定义:类型

echo $PATH
在您提示时

了解它是什么。这是一个用冒号分隔的目录列表。例如,PATH的常用值是

/usr/local/bin:/usr/bin:/bin

表示要按顺序在目录/usr/local/bin/usr/bin/bin中查找程序;换句话说,使用PATH的值以及上面的参数,env首先会尝试运行

/usr/local/bin/node ./foo.js a b c d

,如果没有用,请尝试/usr/bin/node,依此类推。如果您不知道节点解释器(或任何其他地方)的安装位置,则必须使用此额外的间接寻址,因为内核的#!处理将仅接受#!之后的绝对路径名;它不会为您执行PATH搜索。如果您确实知道安装了node的位置,最好直接编写该路径名,这样程序的行为就不会取决于调用用户的PATH是什么(例如some Linux distributions used to use the name /usr/bin/node for a completely unrelated program,因此如果#! /usr/bin/env node,并且用户在PATH上的/opt/node-1.9/bin之前没有/usr/bin,就会引起欢笑。


我为execve和以#!开头的文件描述的行为是 not specified by POSIX(在该问题上已提到 页,但仅在非标准化RATIONALE部分中)。但是,在当今您可能会遇到的所有类Unix操作系统中,它都是一致的。我不知道到底是几岁。