使用 Bash 编写 JSON 文件的最有效方法是什么?

What is the most efficient way of writing a JSON file with Bash?

所以我必须用 bash 脚本写一个 JSON 文件,我知道我可以做类似 echo 'something' >> $file 的事情来慢慢构建一个文件,但是回显重定向而不是真正的文件输出似乎有点 "hacky." 如果这是最好的方式,而不是一个 hacky 方式,我很乐意使用 echo, 但我只是想知道是否有更好的方式来输出文件来自 bash 脚本。

除了echo,您还可以使用cat:

cat > myfile << EOF
Hello
World
!
EOF

您可以使用 cathere-document format:

cat <<'EOF' > output.json
{
    "key": "value",
    "num": 5,
    "tags": ["good", "bad"],
    "money": "[=10=]"
}
EOF

请注意此处文档锚点周围的单个勾号。这可以防止插入文档的内容。没有它,[=12=] 可以被替换。

如果您将效率定义为原始速度而不是可读性,您应该考虑使用 ,因为它对于少量行来说几乎快一个数量级(echo 0.01s vs cat0.1s).
如果您需要创建大于几百行的文件,您应该考虑 cat/echo.

以外的方法

高效生成输出

echo 是内置命令,不是外部命令,因此它并不像您想象的那样低效。 效率低下的是将 >> filename 放在每个 echo.

的末尾

这很糟糕:

# EVIL!
echo "something" >file
echo "first line" >>file
echo "second line" >>file

这个不错:

# NOT EVIL!
{
  echo "something" >&3
  printf '%s\n' "first line" "$second line" >&3
  # ... etc ...
} 3>file

...只打开一次输出文件,消除了主要的低效问题。

明确一点:调用 echo,比如说,调用 20 次比调用 cat 一次要有效得多,因为 cat 是一个外部进程,而不是shell. 运行 echo "foo" >>file 20 次效率极低的部分是打开和关闭输出文件 20 次;这不是 echo 本身。


正确生成JSON

不要使用 catechoprintf 或任何其他类似的东西。相反,使用理解 JSON 的工具——任何其他方法都可能导致不正确的结果(甚至可能通过注入攻击被利用)。

例如:

jq \
  --arg something "$some_value_here" \
  --arg another "$another_value" \
  '.["something"]=$something | .["another_value"]=$another' \
  <template.json >output.json

...将基于 template.json 生成一个 JSON 文件,其中 something 设置为 shell 变量 "$some_value_here" 中的值,并且another_value 设置为第二个值。与天真的方法不同,这将正确处理包含文字引号或其他需要转义才能正确表示的字符的变量值。


echo 旁白

上面已经说过 - echo 应该避免使用 printf(使用适当的静态格式字符串)。 Per the POSIX sh standard:

APPLICATION USAGE

It is not possible to use echo portably across all POSIX systems unless both -n (as the first argument) and escape sequences are omitted.

The printf utility can be used portably to emulate any of the traditional behaviors of the echo utility as follows (assuming that IFS has its standard value or is unset):

[...]

New applications are encouraged to use printf instead of echo.

RATIONALE

The echo utility has not been made obsolescent because of its extremely widespread use in historical applications. Conforming applications that wish to do prompting without s or that could possibly be expecting to echo a -n, should use the printf utility derived from the Ninth Edition system.

As specified, echo writes its arguments in the simplest of ways. The two different historical versions of echo vary in fatally incompatible ways.

The BSD echo checks the first argument for the string -n which causes it to suppress the that would otherwise follow the final argument in the output.

The System V echo does not support any options, but allows escape sequences within its operands, as described for XSI implementations in the OPERANDS section.

The echo utility does not support Utility Syntax Guideline 10 because historical applications depend on echo to echo all of its arguments, except for the -n option in the BSD version.

您可以使用 cat 和 "heredocs" 来尽量减少必须拨打的电话数量。

$ cat foo.sh
cat <<'HERE' > output
This
that
the other
    indentation is 
        preserved

as are 

    blank lines

The end.
HERE
$ sh foo.sh
$ cat output
This
that
the other
    indentation is 
        preserved

as are 

    blank lines

The end.

在环境变量中构造数据,并回显一次。

var=something
var="$var something else"
var="$var and another thing"
echo "$var" > file