如何使用 Google 的 zx 库在 Node 中编写 Shell 脚本
在本文中,我们将了解 Google 的 zx 库提供了哪些功能,以及如何使用它来编写 Node.js 的 shell 脚本。然后,我们将学习如何通过构建一个命令行工具来使用 zx 的功能,该工具可帮助我们引导新 Node.js 项目的配置。
关键要点
Google 的 zx 库简化了 Node.js 中的 shell 脚本,通过利用 JavaScript 和内置实用程序使其更容易、更高效。
Zx 包装子进程创建并使用诸如用于执行 shell 命令的 `$` 函数之类的实用程序简化 stdout 和 stderr 处理。
Zx 通过附加工具(如“cd()”、“question()”)以及对流行库(如“chalk”、“minimist”、“fetch”和“fs-extra”)的访问增强了脚本功能。
为了有效地使用 zx,应该将脚本设置为 ECMAScript 模块,并且应该将 zx 安装为本地依赖项以管理项目内的版本控制。
Zx 与 TypeScript 兼容,需要进行一些配置调整,并可能将异步代码包装在立即调用的函数表达式(IIFE)中。
本教程演示了如何使用 zx 构建项目引导工具,该工具可自动执行设置新的 Node.js 项目、初始化 Git 和管理 npm 依赖项等任务。
编写 Shell 脚本:问题
创建 shell 脚本(由 Bash 或 zsh 等 shell 执行的脚本)是自动执行重复任务的好方法。Node.js 似乎是编写 shell 脚本的理想选择,因为它为我们提供了许多核心模块,并允许我们导入我们选择的任何库。它还使我们能够访问 JavaScript 提供的语言功能和内置函数。
但是,如果您尝试编写在 Node.js 下运行的 shell 脚本,您可能会发现它并不像您希望的那样顺利。您需要为子进程编写特殊处理,处理命令行参数的转义,然后最终弄乱stdout
(标准输出)和stderr
(标准错误)。它不是特别直观,并且会使 shell 脚本编写非常尴尬。
Bash shell 脚本语言是编写 shell 脚本的流行选择。无需编写代码来处理子进程,并且它具有用于处理stdout
和的内置语言功能stderr
。但使用 Bash 编写 shell 脚本也并非易事。语法可能相当混乱,难以实现逻辑或处理诸如提示用户输入之类的事情。
Google 的 zx库有助于使使用 Node.js 的 shell 脚本编写变得高效且愉快。
跟随的要求
遵循本文有一些要求:
理想情况下,您应该熟悉 JavaScript 和 Node.js 的基础知识。
您需要能够熟练地在终端中运行命令。
您需要安装Node.js >= v14.13.1。
Google 的 zx 如何工作?
Google 的 zx 提供了一些函数,用于包装子进程的创建以及这些进程的处理stdout
。stderr
我们将使用的主要函数是该$
函数。下面是它的实际示例:
import { $ } from "zx"; await $`ls`;
以下是执行该代码的输出:
$ ls bootstrap-tool hello-world node_modules package.json README.md typescript
上面示例中的 JavaScript 语法可能看起来有点奇怪。它使用了一种称为标记模板文字的语言功能。其功能与编写相同await $("ls")
。
Google 的 zx 提供了其他几个实用函数来简化 shell 脚本编写,例如:
cd()
.这使我们能够改变当前的工作目录。question()
。这是 Node.js readline模块的包装器。它可以直接提示用户输入。
除了 zx 提供的实用功能外,它还为我们提供了几个流行的库,例如:
Chalk。该库允许我们为脚本的输出添加颜色。
minimist。解析命令行参数的库。然后它们在
argv
对象下公开。fetch 。Fetch API的一个流行 Node.js 实现。我们可以使用它来发出 HTTP 请求。
fs-extra . 一个公开 Node.js 核心fs 模块的库,以及许多附加方法,使使用文件系统变得更加容易。
现在我们知道了 zx 给我们提供了什么,让我们用它创建我们的第一个 shell 脚本。
使用 Google 的 zx 来创建 Hello World
首先,让我们创建一个新项目:
mkdir zx-shell-scripts cd zx-shell-scripts npm init --yes
然后我们可以安装该zx
库:
npm install --save-dev zx
注意:zx
文档建议使用 npm 全局安装库。通过将其作为我们项目的本地依赖项安装,我们可以确保 zx 始终安装,并控制我们的 shell 脚本使用的版本。
顶层await
为了await
在 Node.js 中使用 top-level (await
在函数之外),我们需要在支持 top-level 的ECMAScript (ES) 模块async
中编写代码。我们可以通过添加来指示项目中的所有模块都是 ES 模块,或者我们可以将各个脚本的文件扩展名设置为。我们将使用文件扩展名作为本文中的示例。await
"type": "module"
package.json
.mjs
.mjs
运行命令并捕获其输出
让我们创建一个名为 的新脚本hello-world.mjs
。我们将添加一个shebang 行,它告诉操作系统 (OS)内核使用node
程序运行该脚本:
#! /usr/bin/env node
现在我们将添加一些使用 zx 运行命令的代码。
在下面的代码中,我们运行一个命令来执行ls程序。该ls
程序将列出当前工作目录(脚本所在的目录)中的文件。我们将从命令的进程中捕获标准输出,将其存储在变量中,然后将其记录到终端:
// hello-world.mjs import { $ } from "zx"; const output = (await $`ls`).stdout; console.log(output);
注意:zx
文档建议将/usr/bin/env zx
shebang 行放入脚本中,但我们使用的/usr/bin/env node
是。这是因为我们已经将其安装zx
为项目的本地依赖项。然后,我们明确地从包中导入我们想要使用的函数和对象zx
。这有助于明确说明脚本中使用的依赖项来自何处。
然后我们使用chmod使脚本可执行:
chmod u+x hello-world.mjs
让我们运行脚本:
./hello-world.mjs
我们现在应该看到以下输出:
$ ls hello-world.mjs node_modules package.json package-lock.json README.md hello-world.mjs node_modules package.json package-lock.json README.md
您会注意到我们的 shell 脚本输出中的几件事:
我们运行的命令(
ls
)包含在输出中。该命令的输出显示两次。
输出末尾有一个额外的新行。
zx
默认情况下,它以模式运行verbose
。它将输出您传递给函数的命令$
,并输出该命令的标准输出。我们可以在运行命令之前添加以下代码行来更改此行为ls
:
$.verbose = false;
大多数命令行程序(例如ls
)都会在输出末尾输出一个换行符,以使终端中的输出更具可读性。这有利于提高可读性,但由于我们将输出存储在变量中,因此我们不需要这个额外的换行符。我们可以使用 JavaScript String#trim()函数将其删除:
const output = (await $`ls`).stdout; const output = (await $`ls`).stdout.trim();
如果我们再次运行脚本,我们会看到情况好多了:
hello-world.mjs node_modules package.json package-lock.json
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。