Skip to content

Latest commit

 

History

History
256 lines (165 loc) · 7.61 KB

使用 zx 编写在 Node 中编写 Bash 脚本.md

File metadata and controls

256 lines (165 loc) · 7.61 KB

使用 zx 编写在 Node 中编写 Bash 脚本

Bash 是一种命令语言,通常作为命令行解释程序出现,用户可以在其中从他们的终端软件执行命令。例如,我们可以使用 Ubuntu 的终端来运行 Bash 命令。我们还可以通过 shell 脚本创建和运行 Bash 脚本文件。

我们经常在许多自动化场景中使用 shell 脚本,例如构建过程、CI/CD 或与计算机维护相关的活动。作为一种功能齐全的命令语言,Bash 支持管道、变量、函数、控制语句和基本算术运算。

然而,Bash 不是一种通用的开发人员友好型编程语言。它不支持 OOP、JSON 等结构、数组以外的通用数据结构,以及内置的字符串或数组操作方法。这意味着程序员通常需要从 Bash 中调用单独的 Python 或 Node 脚本来满足这些需求。

这就是 zx 项目的用武之地。zx 引入了一种使用 JavaScript 编写类似 Bash 的脚本的方法。

相比之下,JavaScript 几乎具有开发人员所需的所有内置功能。zx 允许我们通过为几个关键的 CLI 相关 Node.js 包提供包装 API(如:child_process),用 JavaScript 编写 shell 脚本。因此,可以使用 zx 编写开发人员友好的、类似 Bash 的 shell 脚本。

本文将介绍 zx 的一些用法,如何在项目中使用它。

zx 是如何工作的?

每个 zx shell 脚本文件都有 .mjs 扩展名。第三方 API 的所有内置函数和包装器都是预先导入的。因此,你不必在基于 JavaScript 的 shell 脚本中使用额外的 import 语句。

zx 接受来自标准输入、文件和 URL 的脚本。它将你的 zx 命令集导入为 ECMAScript 模块(MJS)来执行,命令执行过程使用 Node.js 的 child_process API

安装

全局安装 zx:

npm i -g zx

版本要求:node >= 16.0.0

在终端运行 zx 以检查程序是否已成功安装:

zx

zx 7.1.1
   A tool for writing better scripts
# ...

你也可以单独在项目引入。

#!/usr/bin/env node

import { $ } from 'zx'
await $`date`

顶层 await

为了在 Node.js 中使用顶级 await,在异步函数之外进行 await,我们需要在 ES 模块中编写代码,它支持顶级 await

我们可以通过在 package.json 中添加 "type": "module" 来表示项目中的所有模块都是 ES 模块,或者我们可以将单个脚本的文件扩展名设置为 .mjs

基本语法

首先,文件扩展使用 .mjs 以便可以在顶层使用 await,如果你还是喜欢原来的 .js,需要包装一个 async 函数。

其次,需要在文件的顶部加上 #!/usr/bin/env zx

以下是获取项目的当前 Git 分支示例:

// demo.mjs
#!/usr/bin/env zx

const branch = await $`git branch --show-current`
console.log(`当前分支:${branch}`)
  • #!/usr/bin/env zx 告诉操作系统的脚本执行器选择正确的解释器。
  • $ 是一个函数,它执行给定的命令,并在与 await 关键字一起使用时返回其输出。

最后,我们使用 console.log 来显示当前分支。

运行脚本,以获取项目的当前 Git 分支:

zx demo.mjs

它还将显示你执行的每个命令,因为 zx 在默认情况下打开了详细模式。

通过添加以下内容,即可消除额外的命令详细信息。

$.verbose = false

由于我们在第一行使用了 shebang#!),我们也可以在不使用 zx 命令的情况下运行脚本。

chmod +x ./demo.mjs

颜色和格式

zx 暴露了 chalk API。因此,我们可以使用它进行着色和格式化,如下所示。

#!/usr/bin/env zx

$.verbose = false

let branch = 1
chalk.level = 1
console.log(`当前分支:${chalk.red.bold(branch)}`)

查看 chalk 的官方文档以了解更多的着色和格式化方法。

用户输入和命令行参数

zx 提供提问功能,从命令行界面捕获用户输入。你还可以使用选项来启用传统的 UNIX 选项卡完成功能。

它使用的是 Node 的 readline 模块。

以下脚本将捕获文件名和模板。它使用用户输入的配置构建一个文件。

#!/usr/bin/env zx

$.verbose = false

let filename = await question('输入文件名: ')
let template = await question('输入你最喜欢的模板:  ', {
  choices: ['function', 'class']
})
let content = ''

if (template == 'function') {
  content = `function main() {
  console.log('Test')
}`
} else if (template == 'class') {
  content = `class Main {
  constructor() {
    console.log('Test')
  }
}`
} else {
  console.error(`无效模板: ${template}`)
  process.exit()
}

fs.outputFileSync(filename, content)

已解析的命令行参数对象可作为全局 argv 常量使用。解析是使用 minimist 模块完成的。

下面的示例捕获了两个命令行参数值。

#!/usr/bin/env zx

$.verbose = false

const size = argv.size
const isFullScreen = argv.fullscreen

console.log(`size=${size}`)
console.log(`fullscreen=${isFullScreen}`)

运行上述脚本文件,以检查命令行参数的支持。

$ zx ./demo .mjs --size=1080 --fullscreen

# size=1080
# fullscreen=true

网络请求

我们经常使用 curl 命令通过 Bash 脚本发出 HTTP 请求。zx 为 node-fetch 模块提供了一个包装器,它将特定模块的 API 公开为 fetch。优点是 zx 不会像 Bash 使用 curl 那样为每个网络请求生成多个进程,因为 node-fetch 包使用 Node 标准的 HTTP API 来发送网络请求。

以下使用 zx 发送 HTTP 请求:

#!/usr/bin/env zx

$.verbose = false

let response = await fetch('https://jsonplaceholder.typicode.com/todos/1')
if (response.ok) console.log(await response.text())

/*
{
  "userId": 1,
  "id": 1,
  "title": "delectus aut autem",
  "completed": false
}
*/

构建命令管道

在 shell 脚本中,管道指的是多个顺序执行的命令。我们经常在 shell 脚本中使用众所周知的管道字符(|),将输出从一个进程传递到另一个进程。zx 提供了两种不同的方法来构建管道。

我们可以将 | 字符与类似于 Bash 脚本的命令集一起使用,或者我们也可以使用 zx 内置 API 中的 pipe() 方法。

使用 |

#!/usr/bin/env zx

$.verbose = false

let greeting = await $`echo "hello World" | tr '[h]' [H]`
console.log(`${greeting}`)

使用 pipe()

#!/usr/bin/env zx

$.verbose = false

let greeting = await $`echo "Hello world"`.pipe($`tr '[w]' [W]`)
console.log(`${greeting}`)

高级用法

除了基于 JavaScript 的 shell 脚本支持外,zx 还支持其他一些有用的功能。

默认情况下,zx 使用 Bash 解释器来运行命令。我们可以通过修改 $.shell 来更改默认 shell 配置变量。下面的脚本使用 sh shell 而不是 bash。

$.shell = '/usr/bin/sh'
$.prefix = 'set -e;'

$`echo "Your shell is $0"` // Your shell is /usr/bin/sh

更多配置命令可以查看 Configuration

zx 命令行程序也可以从 URL 运行远程脚本。以提供文件名的方式提供 zx 脚本的链接。

以下是 zx 文档提供的一个示例:

zx https://medv.io/game-of-life.js

其他:

  • 与 TypeScript 一起使用
  • GitHub Actions
  • etc

详细内容可以查看官方文档