使用 NPX 命令作为 shell 脚本的 shebang/解释器。

6

我想使用coffee可执行程序运行命令行脚本,但我想通过npx调用该可执行程序。

#!/usr/bin/env npx coffee这样的东西不起作用,因为env只支持一个参数。

那么,有没有办法通过env运行一个npx可执行程序呢?


5
根据Unix&Linux Stack Exchange的一个回答,评论似乎相关,但似乎不符合答案标准。从coreutils 8.30开始,您将能够使用“-S”选项传递多个参数。现在在MacOS上可以使用TypeScript的shebang:`#!/usr/bin/env -S npx ts-node --compiler-options {"module":"commonjs"}`不幸的是,在Debian Buster上还不能使用。 - Scott Willeke
我的当前理解是,每当node检测到npx包的shebang时,它就会插入一个“shell”/“cmd” shims。从cmd shim中,它接受多个参数。我不知道有没有任何文档记录它,但它在代码中:https://github.com/npm/cmd-shim/blob/f59af911f1373239a7537072641d55ff882c3701/index.js#L22 - DaMaxContent
1个回答

0

这里有一个使用ts-node的解决方案。

任何单一操作系统,全局安装ts-node

#!/usr/bin/env ts-node

// TypeScript code

您可能还需要全局安装 @swc/core@swc/cli,除非您进行了进一步的配置或调整(请参见末尾的注释)。如果您遇到任何与它们有关的问题,请确保安装最新版本。

macOS,ts-node 未全局安装

#!/usr/bin/env npx ts-node

// TypeScript code

在 macOS 上是否总是有效尚不清楚。可能会有一些魔法与节点 安装 shell 命令 shim 有关(感谢 @DaMaxContext 的评论)。

这在 Linux 中不起作用,因为 Linux 发行版将 env 后的所有字符都视为命令,而不是将空格视为分隔不同参数。或者如果节点命令 shim 不存在,则在 Linux 中不起作用(尚未确认它的工作方式,但在我的测试中,它在 Linux Docker 容器中不起作用)。

这意味着 npx ts-node 将被视为一个具有空格的单个可执行文件名称,这显然不起作用,因为那不是一个可执行文件。

有关 npx 缓慢性的注释,请参见底部说明。

跨平台使用 ts-node 在 macOS 上未全局安装,并在 Linux 中进行一些设置

创建一个 shebang,可以在 macOS 和 Linux(或在运行 Linux 映像的 Docker 中使用 macOS)中工作,而无需在 macOS 中全局安装 ts-node 和其他依赖项,如果愿意在 Linux/Docker 方面进行一些设置,则可以实现。显然,Linux 必须安装 node

使用#!/usr/bin/env npx ts-node shebang。我们只需要欺骗Linux以为带有空格的npx ts-node实际上是一个有效的可执行文件名。
构建一个命名的Docker镜像,该镜像已全局安装所需的依赖项和符号链接,使npx ts-node解析为ts-node
以下是在macOS上的示例一体化命令行,它将同时构建此映像并运行它:
docker buildx build -t node-ts - << EOF FROM node:16-alpine RUN \ npm install -g @swc/cli @swc/core ts-node \ && ln -s /usr/local/bin/ts-node '/usr/local/bin/npx ts-node' ENV SWC_BINARY_PATH=/usr/local/lib/node_modules/@swc/core/binding WORKDIR /app EOF
docker run -it --rm \ -v "$(pwd):/app" \ node-ts \ sh
请注意,为使此示例脚本正常工作,包含EOF的上面一行不能有任何其他字符,包括空格。
在运行的容器内,所有可执行.ts脚本chmod +x script.ts都可以通过从命令行运行它们来执行,例如./test-script.ts。您还可以将上面的sh替换为脚本的名称(但一定要在前面加上./,以便Docker知道将其作为可执行文件运行而不是将其传递为node的参数)。

其他想法和考虑

有其他方法可以实现所需的功能。

  • docker run 命令可以将文件挂载到镜像中,包括在各个目录中挂载可执行文件。巧妙地使用此功能可以避免需要先安装任何内容或构建 Docker 镜像。
  • 安装命令可以作为 docker run 的一部分而不是预先构建镜像,但这样会在每次执行时执行,时间会更长。
  • 可以在 macOS、Linux 和 docker build 中修改 PATH,以添加包含 ts-node 的 bin.js 的文件夹,该文件夹来自于任何 ts-node 的 dist 目录,然后使用 #!/usr/bin/env bin.js 的 shebang 理论上应该可以工作(也可以尝试使用 bin-esm.js 来避免需要 SWC,虽然这会进入实验性的 Node 领域,可能不适合生产脚本)。这在 macOS 中、在不属于 npm 项目的 Docker 中以及在配置为使用 TS 和 swc 的 npm 项目内的 Docker 中均可工作,通过向 ts-node 传递 --skipProject 标志或设置环境变量 TS_NODE_SKIP_PROJECT=true 来实现。一个可行的测试命令行示例:docker run -it --rm -v "$(pwd):/app" -e TS_NODE_SKIP_PROJECT=true -w /app --entrypoint sh node:16-alpine -c 'PATH="$PATH:/app/node_modules/ts-node/dist" ./test.ts'
  • 任何可以在 PATH 中找到并通过直接命令运行的命名可执行文件都可以成为 shebang(使用 #!/usr/bin/env executable)。它可以是 shell 脚本、二进制文件或任何其他类型的文件。可以将 shell 脚本轻松放置在已知位置,添加到 PATH 中,然后调用您喜欢的任何内容。它可以是多语句的,将文件编译为 .js,然后运行该文件。无论您的需求是什么。
  • 在某些特殊情况下,您可能只想使用 node 作为 shebang 可执行文件,并通过环境变量设置 node 选项来强制使用 ts-node 作为加载器。有关更多信息,请参见 ts-node Recipes:Other

注释:

  • SWC_BINARY_PATH 环境变量 确保 ts-node 能够找到特定架构的 swc 编译器(避免错误“Bindings not found”)。如果您只在一个架构上运行,那么您就不需要它。或者,如果您挂载了已经安装了这些 @swc 包(是正确架构)的 node_modules,那么您不需要它。
  • 可以为多个架构安装 node_modules 二进制文件。这样做的方式因不同的包管理器而异。例如,yarn 3 允许您在 .yarnrc.yml 中一次性定义要安装的二进制文件。使用环境变量,npm 和可能的 yarn 1(和 2?)也有其他选项。
  • ts-node 提供了无需 swc 运行的选项(虽然速度较慢)。您可以尝试使用带有 ts-node-esm 的 shebangs 代替 ts-node。查看 /usr/local/bin 文件夹中的所有符号链接或参考 ts-node 文档以获取更多信息。
  • 可以直接使用 node 运行 .ts 文件,并在环境变量中设置 node 选项。node --loader=ts-node 在最近版本(16+?)中可以使用。实验模式警告可以被抑制。
  • 有一些疯狂的方法可以欺骗 shell 运行 JavaScript 而不是 unix shell。请查看 这个答案,它使用普通的 sh shebang,但 clever shell 语句将执行转移到基本上被 JavaScript 忽略的 node 上。这并不好,因为它需要额外的把戏行,但可能会帮助一些人。页面上的其他答案也很有教育意义,值得审查以获取完整的图片。
  • 如果在 npm 项目之外运行 .ts 文件,则此处的某些复杂性可能会消失。在我自己的 Docker 测试中,上下文始终在具有自己的 tsconfig.json 和已安装的 swc 的项目中,因此您可能会获得不同的结果。很难让 ts-node 忽略执行的 .ts 文件找到的 npm 项目上下文。
  • ESM 和 CommonJS 模块处理的差异没有在此处解释。这是一个复杂的主题,超出了这个答案的范围。
  • 简而言之,如果您能够弄清如何以 executable [options] [file] 的形式从命令行运行脚本,那么您应该能够通过混合和匹配这里介绍的所有思路来弄清如何使用适当的 shebang 运行 ./[file]。您不必使用 ts-node。您可以直接使用 nodeswctsc 本身(首先编译,然后在找到的上下文中运行任何 .js 文件或一组 .js 文件),或任何能够编译或运行 TypeScript 的实用程序或工具。
请注意,使用 npx 比直接运行 ts-node 要慢得多,因为每次运行时它可能需要下载 ts-node 包和依赖项。
以下是一些关于 SWC 架构支持的各种随机提示:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接