问题描述
我正在尝试创建一个bash脚本来自动配置一些letencrypt相关的东西。
我必须编辑的文件是json,所以我只能使用 git commit -m "xxx"
git stash pop
对其进行编辑,并从脚本的位置参数中将站点名称传递给它,但是我无法通过位置参数进入json文本。
我正在尝试做如下事情:
jq
第二个位置参数(JSON=`jq '. + { "ssl_certificate": "/etc/letsencrypt/live/$2/fullchain.pem" }' <<< echo site_config.json`
JSON=`jq '. + { "ssl_certificate_key": "/etc/letsencrypt/live/$2/fullchain.pem" }' <<< ${JSON}`
echo -e "$JSON" > site_config.json
)包含需要在json文件中设置的域名。
这怎么办?
原始json:
$2
想要的json:
{
"key1":"value1","key2":"value2"
}
解决方法
1。 bash
下的字符串构造我使用printf
和 octal 表示法来嵌套引号和双引号:
printf -v JSON 'Some "double quoted: \047%s\047"' "Any string"
echo "$JSON"
Some "double quoted: 'Any string'"
2。使用jq
,严格回答已编辑的问题:
myFunc() {
local file="$1" site="$2" JSON
printf -v JSON '. + {
"ssl_certificate": "/etc/letsencrypt/live/%s/fullchain.pem","ssl_certificate_key": "/etc/letsencrypt/live/%s/fullchain.pem"
}' "$site" "$site"
jq "$JSON" <"$file"
}
然后运行:
myFunc site_config.json test.com
{
"key1": "value1","key2": "value2","ssl_certificate": "/etc/letsencrypt/live/test.com/fullchain.pem","ssl_certificate_key": "/etc/letsencrypt/live/test.com/fullchain.pem"
}
myFunc site_config.json test.com >site_config.temp && mv site_config.{temp,conf}
甚至:
myFunc <(
printf '{ "key1":"value1","key2":"value2","comment":"Let\047s doit\041" }'
) test.com
将渲染:
{
"key1": "value1","comment": "Let's doit!","ssl_certificate_key": "/etc/letsencrypt/live/test.com/fullchain.pem"
}
2b。最好使用jq
的{{1}}选项:
我使用bash数组存储带引号,空格和其他特殊字符的字符串。这更具可读性,因为不需要转义行尾(反斜杠)并允许注释:
--arg
3。内联编辑功能
用于编辑小脚本。我更喜欢使用myFunc() {
local file="$1" site="$2"
local JSON=(
--arg ssl_certificate "/etc/letsencrypt/live/$site/fullchain.pem"
--arg ssl_certificate_key "/etc/letsencrypt/live/$site/fullchain.pem"
'. + {$ssl_certificate,$ssl_certificate_key}' # this syntax
# do offer two advantages: 1: no backslashes and 2: permit comments.
)
jq "${JSON[@]}" <"$file"
}
来保存
属性,并确保在更换之前进行有效的操作。
如果您打算使用它(主要用于替换),则可以在函数中添加替换:
cp -a
然后修改文件而不是将结果转储到终端,必须添加myFunc() {
local REPLACE=false
[ "$1" = "-r" ] && REPLACE=true && shift
local file="$1" site="$2"
local JSON=( --arg ssl_certificate "/etc/letsencrypt/live/$site/fullchain.pem"
--arg ssl_certificate_key "/etc/letsencrypt/live/$site/fullchain.pem"
'. + {$ssl_certificate,$ssl_certificate_key}' )
if $REPLACE;then
cp -a "$file" "${file}.temp"
exec {out}>"${file}.temp"
else
exec {out}>&1
fi
jq "${JSON[@]}" <"$file" >&$out &&
$REPLACE && mv "${file}.temp" "$file"
exec {out}>&-
}
选项:
-r
,
我无法将位置参数传递给json文本。
通常,到目前为止,最好的方法是使用jq的--arg和/或--argjson命令行选项。这是安全的,并且在当前情况下意味着您只需要调用一次jq。例如:
< site_config.json \
jq --arg sslc "/etc/letsencrypt/live/$2/fullchain.pem" \
--arg sslck "/etc/letsencrypt/live/$2/fullchain.pem" '
. + {ssl_certificate: $sslc,ssl_certificate_key: $sslck }'
确定一切正常后,请随时使用moreutils的sponge
:-)
DRY-er解决方案
由于jq具有整洁的便利功能,因此可以编写更多DRY-ly:
< site_config.json \
jq --arg ssl_certificate "/etc/letsencrypt/live/$2/fullchain.pem" \
--arg ssl_certificate_key "/etc/letsencrypt/live/$2/fullchain.pem" '
. + {$ssl_certificate,$ssl_certificate_key }'
``
,
使用不同的引号和set
来查看发生的事情...
set -x
JSON=$(jq ". + { \"ssl_certificate\": \"/etc/letsencrypt/live/${2}/fullchain.pem\" }" <<< echo site_config.json)
JSON=$(jq ". + { \"ssl_certificate_key\": \"/etc/letsencrypt/live/${2}/fullchain.pem\" }" <<< ${JSON})
echo -ne "${JSON}" > site_config.json
set +x
...代替反引号以提高阅读质量:$(command argument)
参数必须用双引号引起来。单引号无效。