I'm trying to create a bash script that automates configuration of some letsencrypt related stuff.
The file that I have to edit is json so I would just use jq
to edit it and pass the site name to it from the positional arguments of the script, but I can't get the positional argument passed into the json text.
I'm trying to do domething like the following:
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
Where the second positional argument ($2
) contain the domain name required to be set in the json file.
How this can be done?
Original json:
{
"key1":"value1",
"key2":"value2"
}
Wanted json:
{
"key1":"value1",
"key2":"value2",
"ssl_certificate": "/etc/letsencrypt/live/somesite.com/fullchain.pem",
"ssl_certificate_key": "/etc/letsencrypt/live/somesite.com/fullchain.pem"
}
I use printf
and octal representation for nesting quotes and double quotes:
printf -v JSON 'Some "double quoted: \047%s\047"' "Any string"
echo "$JSON"
Some "double quoted: 'Any string'"
jq
, strictly answer to edited question: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"
}
Then run:
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}
Or even:
myFunc <(
printf '{ "key1":"value1","key2":"value2","comment":"Let\047s doit\041" }'
) test.com
Will render:
{
"key1": "value1",
"key2": "value2",
"comment": "Let's doit!",
"ssl_certificate": "/etc/letsencrypt/live/test.com/fullchain.pem",
"ssl_certificate_key": "/etc/letsencrypt/live/test.com/fullchain.pem"
}
jq
's --arg
option:Thanks to peak's detailed answer!
I use bash arrays to store strings with quotes, spaces and other special characters. This is more readable as there is no need to escape end-of-line (backslashes) and permit comments:
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"
}
For editing a small script. I prefer to use cp -a
in order to preserve
attributes and ensure a valid operation before replacement.
If you plan to use this, mostly for replacing, you could add replacement in your function:
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}>&-
}
Then to modify file instead of dumping result to terminal, you have to add -r
option:
myFunc -r site_config.json test.org