通用 Node.js shebang?

通用 Node.js shebang?

Node.js这些天很受欢迎,我一直在用它写一些脚本。不幸的是,兼容性是一个问题。正式地,Node.js 解释器应该被称为node,但 Debian 和 Ubuntu 提供了一个名为 的可执行文件nodejs

我想要 Node.js 可以在尽可能多的情况下使用的可移植脚本。假设文件名是foo.js,我真的希望脚本以两种方式运行:

  1. ./foo.jsnode如果或nodejs位于 中,则运行脚本$PATH
  2. node foo.js还运行脚本(假设解释器被调用node

笔记:xavierm02 和我自己的答案是多语言脚本的两种变体。我仍然对纯粹的 shebang 解决方案感兴趣(如果存在的话)。

答案1

我想出的最好的办法是这个“两行 shebang”,它实际上是一个多语言(Bourne shell / Node.js)脚本:

#!/bin/sh
':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@"

console.log('Hello world!');

显然,第一行是 Bourne shell shebang。 Node.js 会绕过它找到的任何 shebang,因此就 Node.js 而言,这是一个有效的 javascript 文件。

:第二行使用参数调用 shell no-op //,然后使用该文件的名称作为参数执行nodejsor 。用来代替便携性。命令替换语法并不严格是 Bourne,因此如果您在 20 世纪 80 年代运行此命令,请选择反引号。nodecommand -vwhich$(...)

Node.js 只是评估 string ':',这就像一个无操作,并且该行的其余部分被解析为注释。

文件的其余部分只是普通的旧 JavaScript。子 shell 在exec第二行完成后退出,因此 shell 永远不会读取文件的其余部分。

感谢 xavierm02 的灵感以及所有评论者提供的更多信息!

答案2

这只是基于 Debian 的系统上的一个问题,在该系统上策略克服了意义。

我不知道Fedora什么时候提供了一个名为nodejs的二进制文件,但我从未见过它。该软件包称为nodejs,它安装一个名为node.js 的二进制文件。

只需使用符号链接将常识应用到基于 Debian 的系统,然后您就可以使用理智的 shebang。无论如何,其他人都会使用 sane shebangs,所以你将需要该符号链接。

#!/usr/bin/env node

console.log("Spread the love.");

答案3

#!/bin/sh
//bin/false || `which node || which nodejs` << `tail -n +2 $0`
console.log('ok');

//bin/false与 是相同的,/bin/false只是第二个斜杠将其转换为节点的注释,这就是它在这里的原因。然后,对第一个的右侧||进行评估。'which node || which nodejs'使用反引号而不是引号启动节点并为其<<提供右侧的任何内容。我可以使用//像 dancek 那样以开头的分隔符,它会起作用,但我发现开头只有两行会更干净,所以我过去常常tail -n +2 $0让文件自行读取,除了前两行。

如果您在节点中运行它,第一行将被识别为 shebang 并被忽略,第二行是单行注释。

(显然,sed可以用来代替tail打印文件内容,不包含第一行和最后一行


编辑前回答:

#!/bin/sh
`which node || which nodejs` <<__HERE__
console.log('ok');
__HERE__

你不能做你想做的事,所以你要做的就是运行一个 shell 脚本,因此#!/bin/sh.该 shell 脚本将获取执行节点所需的文件的路径,即which node || which nodejs.反引号在这里以便它被执行,因此'which node || which nodejs'(使用反引号而不是引号)只需调用 node.然后,您只需使用<<.它们__HERE__是您脚本的分隔符。这console.log('ok');是一个脚本示例,您应该将其替换为您的脚本。

答案4

为了完整起见,这里有一些执行第二行的其他方法:

// 2>/dev/null || echo yes
false //|| echo yes

但两者都比所选答案没有任何优势:

':' //; || echo yes

另外,如果您知道会找到其中一个nodenodejs(但不是两者),则可以执行以下操作:

exec `command -v node nodejs` "$0" "$@"

但这是一个很大的“如果”,所以我认为所选的答案仍然是最好的答案。

相关内容