将 heredoc 声明压缩到 bash 中的一行?

Compress heredoc declaration to one line in bash?

我有这个可以在 bash 脚本中声明一个 JSON 字符串:

   local my_var="foobar"
   local json=`cat <<EOF
  {"quicklock":"${my_var}"}
EOF`

上面的 heredoc 有效,但我似乎无法用任何其他方式格式化它,它确实必须看起来完全一样哈哈。

有什么方法可以让命令在一行上,像这样:

   local json=`cat <<EOF{"quicklock":"${my_var}"}EOF`

那会好得多,但似乎并不需要,显然只是因为这不是 EOF 的工作方式,我想哈哈。

我正在寻找一种 shorthand 方法来在文件中声明 JSON:

  1. 不需要大量转义字符。
  2. 这允许变量的动态插值。

注意: 我想使用的实际 JSON 有多个具有许多 key/value 对的动态变量。请推断。

我不是 JSON 人,不太理解上面讨论中的“合式”论点,但是,您可以使用 'here-string' 而不是 'here-document',像这样:

my_var="foobar"
json=`cat <<<{\"quicklock\":\"${my_var}\"}`

因为没有转义字符是强烈要求这里是一个基于 here-doc 的解决方案:

#!/bin/bash

my_var='foobar'

read -r -d '' json << EOF
{
    "quicklock": "$my_var"
}
EOF

echo "$json"

它将为您提供与我提到的第一个解决方案相同的输出。

请注意,如果您先将 EOF 放在双引号内:

read -r -d '' json << "EOF"

$my_var 不会被视为变量,而是纯文本,因此您会得到以下输出:

{
        "quicklock": "$my_var"
}

仅使用 shell 的自然字符串连接怎么样?如果您连接 ${mybar} 而不是插入它,您可以避免转义并将所有内容放在一行中:

my_var1="foobar"
my_var2="quux"
json='{"quicklock":"'${my_var1}'","slowlock":"'$my_var2'"}'

也就是说,这是一个非常粗略的方案,正如其他人所指出的,如果变量包含引号字符,您就会遇到问题。

你可以用 printf 做到这一点:

local json="$(printf '{"quicklock":"%s"}' "$my_var")"

(没关系,SO 的语法突出显示在这里看起来很奇怪。Posix shell 命令替换允许嵌套一层引号。)

注意事项(感谢 ):我假设 $my_var 不受用户输入控制。如果是,您需要小心确保它对于 JSON 字符串是合法的。我强烈建议禁止使用非 ASCII 字符、双引号和反斜杠。如果您有 jq 可用,您可以按照 Charles 在评论中指出的那样使用它,以确保您的输出格式正确。

您可以定义自己的辅助函数来解决缺少 语法的情况:

function begin() { eval echo $(sed "${BASH_LINENO[0]}"'!d;s/.*begin \(.*\) end.*//;s/"/\\"/g' "${BASH_SOURCE[0]}"); }

那么就可以如下使用了

my_var="foobar"

json=$(begin { "quicklock" : "${my_var}" } end)

echo "$json"

此片段显示所需的输出:

{ "quicklock" : "foobar" }

这只是概念验证。您可以以任何您想要的方式定义您的语法(例如通过自定义 EOF 字符串结束输入,正确转义无效字符)。例如,由于 Bash 允许函数标识符使用字母数字字符以外的字符,因此可以定义这样的语法:

json=$(/ { "quicklock" : "${my_var}" } /)

此外,如果放宽第一个条件(转义字符),普通赋值就可以很好地解决这个问题:

json="{ \"quicklock\" : \"${my_var}\" }"

为什么不使用 jq?它非常擅长管理字符串插值,并且可以检查您的结构。

$ echo '{}' >> foo.json
$ local myvar="assigned-var"
$ jq --arg ql $myvar '.quicklock=$ql' foo.json

然后可以将调用 jq 的另一端出现的文本 cat 放入文件或任何您想做的事情中。文字看起来像这样:

{"quicklock"="assigned-var"}