使用 NPX 命令进行 shell 脚本 shebang / 解释器

sur*_*kal 6 shell node.js coffeescript npm npx

我想使用coffee可执行文件运行命令行脚本,但我想通过npx.

类似的东西#!/usr/bin/env npx coffee不起作用,因为通过 只支持一个参数env

那么,有没有办法npx通过运行可执行文件env

Eri*_*ikE 0

这是一个使用的解决方案ts-node

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

#!/usr/bin/env ts-node

// TypeScript code
Run Code Online (Sandbox Code Playgroud)

您可能还需要全局安装@swc/core@swc/cli除非您进行进一步的配置或调整(请参阅最后的注释)。如果您对这些有任何问题,请务必安装最新版本。

macOS,ts-node未全局安装

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

// TypeScript code
Run Code Online (Sandbox Code Playgroud)

这是否总是适用于 macOS 尚不清楚。节点安装 shell 命令垫片可能产生一些魔力(感谢 @DaMaxContext 对此发表评论)。

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

这意味着它将npx ts-node被视为单个可执行文件名称,其中包含空格,这显然不起作用,因为它不是可执行文件。

请参阅底部有关npx缓慢的注释。

跨平台,在 macOS 中ts-node 全局安装,在 linux 中进行了一些设置

如果愿意在 Linux 上进行一些设置,则可以创建一个可在 macOS 和 Linux(或使用 Docker 运行 Linux 映像的 macOS)中运行的 shebang,而无需ts-node在 macOS 中全局安装和其他依赖项/码头工人方面。显然Linux一定已经node安装好了。

  1. 使用#!/usr/bin/env npx ts-node舍邦。我们只需欺骗 Linux 认为npx ts-node带有空格的实际上是一个有效的可执行文件名称。

  2. 构建一个命名的 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
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,要使此示例脚本正常工作,上面的行 containsEOF不得在该行之前或之后包含任何其他字符,包括空格。

  3. 在运行的容器内部,所有.ts已可执行的脚本chmod +x script.ts只需从命令行运行即可执行,例如./test-script.ts. 您也可以将上面的内容替换sh为脚本的名称(但请务必在其前面添加 ,./以便 Docker 知道将其作为可执行文件运行,而不是将其作为参数传递给node)。

其他想法和注意事项

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

  • docker run命令可以将文件挂载到映像中,包括在各个目录中挂载可执行文件。对此进行一些创造性的使用可以避免需要先安装任何东西或构建 docker 镜像。
  • 安装命令可以是 docker run 的一部分,而不是预先构建映像,但随后会在每次执行时执行,从而花费更长的时间。
  • 可以PATH在 macOS、Linux 中进行修改,并从任何 ts-node目录中docker build添加包含 ts-node 的文件夹,然后理论上应该可以工作(并且可以尝试避免需要 SWC,尽管这进入了实验性节点领域,并且可能不适合生产脚本)。这适用于 macOS、npm 项目外部的 Docker 以及配置为通过将标志传递给 ts-node 或设置环境变量来使用 TS 和 swc 的 npm 项目内部的 Docker 。一个有效的测试命令行示例:.bin.jsdist#!/usr/bin/env bin.jsbin-esm.js--skipProjectTS_NODE_SKIP_PROJECT=truedocker 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,然后运行它。无论您的需求是什么。
  • 在某些特殊情况下,您可能只想简单地用作nodeshebang 可执行文件,通过环境变量设置节点选项以强制 ts-node 作为加载程序。有关详细信息,请参阅ts-node Recipes:Other 。

笔记:

  • 环境SWC_BINARY_PATH 变量确保 ts-node 可以找到特定于体系结构的swc编译器(以避免错误“找不到绑定”)。如果您只在一种架构上运行,则不需要它。或者,如果您正在安装node_modules已经为正确的架构安装了这些 @swc 软件包,则您将不需要它。
  • 可以为多个架构安装 node_modules 二进制文件不同的包管理器之间执行此操作的方法有所不同。例如,yarn 3 允许您定义要在.yarnrc.yml. 使用环境变量,npm 和可能的纱线 1(和 2?)还有其他选项。
  • ts-node确实提供了无需 SWC 即可运行的选项(尽管速度较慢)。你可以尝试使用 shebangsts-node-esm而不是ts-node。查看/usr/local/bin文件夹中的所有符号链接或查阅 ts-node 文档以获取更多信息。如果 ts 节点
  • 可以使用节点直接运行 .ts 文件并在环境变量中设置节点选项。node --loader=ts-node在最近的版本(16+?)中确实有效。可以抑制实验模式警告。
  • 有一些疯狂的方法可以欺骗 shell 运行 JavaScript 而不是 unix shell。查看这个答案,它使用普通的shshebang,但巧妙的 shell 语句将执行转移到节点,这基本上被 JavaScript 忽略。这不是很好,因为它需要额外的技巧,但可以帮助一些人。该页面上的其他答案也很有启发性,值得查看以了解完整情况。
  • 如果在npm 项目之外运行.ts文件,这里的一些复杂性可能会消失。在我自己的 Docker 测试中,上下文始终位于拥有自己的且已安装的项目中,因此使用不同的设置可能会得到不同的结果。事实证明,很难忽略执行文件中发现的 npm 项目上下文。tsconfig.jsonswcts-node.ts
  • 这里没有解释 ESM 和 CommonJS 模块处理之间的区别。这是一个复杂的话题,超出了本答案的范围。
  • 可以这么说,如果您能够弄清楚如何从表单中的命令行运行脚本executable [options] [file],那么您应该能够./[file]通过混合和匹配此处提出的所有想法来弄清楚如何使用适当的 shebang 运行。您不必使用 ts-node。您可以直接使用nodeswctsc本身(通过首先编译然后在找到的上下文中运行任何 .js 文件或一组 .js 文件),或任何能够编译或运行 TypeScript 的实用程序或工具。

请注意,使用npx比直接运行要慢得多,因为每次运行时ts-node可能都需要下载包和依赖项。ts-node

关于 SWC 架构支持的可能策略的一些随机提示: