Eval Script via Nodejs

Node.js

在编写 Bash 脚本的过程中,难免会遇到一些单纯用 Linux 命令很难实现的功能,比如,希望将一个文件的内容作为 JSON 的一个字段,并通过 curl 将这个 JSON 数据发送给服务器。如果单纯使用 Linux 的命令来拼接这个 JSON 字符串,在转意上会遇到很大的问题。但其实同样的需求,在 JavaScript 中可以通过一行命令完成:

JSON.stringify({ text: fs.readFileSync(filepath, 'utf8') })

对于这样的情况,如果正好环境中有 Node.js(比如基于 Node 的 Docker 环境),就可以很方便的通过直接调用 Node 来处理这部分的需求。

需要用到 node.js 内建的参数 -e-p

对于 -e 这个参数(或 --eval),Node 会执行参数后面的字符串。类似于 node file.js 可以让 Node.js 执行 file.js 这个文件,node -e "script" 可以让 Node.js 执行 script 这串语句。需要注意的几点:

  1. Windows 的 CMD 不能使用单引号,只能使用双引号;Powershell 的的话,两者都是支持的;
  2. -e 指令并不会将执行的结果输出到终端,因而如果需要 Bash 中能够用变量保存运行结果的话,需要额外使用 console.log 将结果输出到 stdout,然后再由 Bash 传递给需要赋值的变量。

综上所述,上面这个 JSON 序列化的需求,就可以写成下面的这种形式:

node -e "console.log(JSON.stringify({ text: fs.readFileSync(file, 'utf8') }))"

显然,对于需要赋值的情况,每次都加上 console.log 去输出结果比较的繁琐。Node.js 为此提供了另外一个可用的参数 -p。这个参数的表现形式和 -e 几乎是一样的,唯一的区别是,-p 会将结果默认输出到 stdout 中,不需要额外套一层 console.log 来完成这个操作。-p 也可以写作 --print

下面用一个例子来说明两者的区别:

echo $(node -e "true")

上面这个命令运行的结果将输出空字符串;而下面这个命令,则会在终端输出 true

echo $(node -p "true")

如此一来,上面的例子可以进一步转化为:

node -p "JSON.stringify({ text: fs.readFileSync(file, 'utf8') })"

配合 curl 最终的命令大体上如下:

curl -X POST \
  -H "Content-Type: application/json" \
  $URL \
  --data-binary \
    "$(node -p 'JSON.stringify({text:fs.readFileSync("filepath","utf8")})')"