将 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:
- 不需要大量转义字符。
- 这允许变量的动态插值。
注意: 我想使用的实际 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 在评论中指出的那样使用它,以确保您的输出格式正确。
您可以定义自己的辅助函数来解决缺少 bash 语法的情况:
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"}
我有这个可以在 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:
- 不需要大量转义字符。
- 这允许变量的动态插值。
注意: 我想使用的实际 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 在评论中指出的那样使用它,以确保您的输出格式正确。
您可以定义自己的辅助函数来解决缺少 bash 语法的情况:
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"}