在编写 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
这串语句。需要注意的几点:
- Windows 的 CMD 不能使用单引号,只能使用双引号;Powershell 的的话,两者都是支持的;
-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")})')"