【问题标题】:The code that runs when you type `node` at the terminal在终端输入“node”时运行的代码
【发布时间】:2019-01-07 04:50:53
【问题描述】:

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

【问题讨论】:

  • 这在很大程度上取决于操作系统和可执行文件的类型。这是 GNU/Linux 吗?当您在终端输入node 时,通常不涉及任何shebang。你的问题是“shell如何运行像node这样的可执行文件?”或“shell如何运行带有#!/usr/bin/env node之类的shebang的脚本?”
  • 好吧,只是知道当我输入 node 时会发生什么,如果有的话,它首先会碰到 c 库中的代码行。

标签: c node.js bash terminal


【解决方案1】:

准确地说,“shebang”只是#! 这两个字符。当 Unix 系统上的文件作为可执行文件被调用时(最终通过系统调用 execve),内核查看它的前几个字节以确定它是什么种类的可执行文件。如果这些字节将其识别为包含机器代码,那么内核会将机器代码加载到内存中并导致 CPU 开始执行它。如果机器代码是从 C 程序编译的,它的main 函数最终会被调用。 (如果您想了解 过程是如何工作的,请阅读 John Levine 所著的“Linkers and Loaders”一书。)

但如果前两个字节是 #!(ASCII 值 35 和 33),那么内核将改为扫描文件的第一行以查找 解释器的名称,然后它将运行解释器,提供#! 程序的名称作为命令行参数。 (有关内核如何解析第一行的详细信息,请参阅this answer。)如果你这样做了

./foo.js a b c d

而 foo.js 以 #! /usr/bin/node 开头,那么内核的行为就像使用参数向量调用了 execve

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

它会打开文件/usr/bin/node,发现这是一个机器码可执行文件,然后继续加载机器码,它是节点解释器,并运行它。 Node 的 main 函数会注意到它的第一个参数是 ./foo.js,它会打开该文件并将其作为 Javascript 程序执行,而不是进入其交互式读取-评估-打印循环。

Node 解释器本身会忽略#! 行——但它的解析器中必须有代码才能忽略它;内核不会将其过滤掉。对于 Unix 上常用的许多解释语言(sh、awk、perl、python、ruby,...),cmets 从# 运行到行尾,所以这会自动发生;事实上,在过去,#! 符号被选中,因为 sh cmets 是从# 到行尾的。 Javascript cmets 不能这样工作,因此 Node 必须在文件开头有一个 #! 的特殊情况。


您显示的#! 行具有额外的间接级别:#! /usr/bin/env node 使内核使用参数向量运行程序/usr/bin/env(同样由机器代码组成)

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

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

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 等等。如果你不知道 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 和以#! 开头的文件描述的行为不是 specified by POSIX(在该页面上提到,但仅在非规范的基本原理部分)。但是,它在您现在可能遇到的所有类 Unix 操作系统中都是一致的。我完全不知道它到底有多大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-09
    • 2014-02-09
    • 1970-01-01
    • 2016-04-17
    • 2020-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多