1

我正在尝试创建一个 bash 脚本来自动配置一些 letencrypt 相关的东西。

我必须编辑的文件是 json,所以我只是jq用来编辑它并将站点名称从脚本的位置参数传递给它,但我无法将位置参数传递到 json 文本中。

我正在尝试执行以下操作:

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

其中第二个位置参数 ( $2) 包含需要在 json 文件中设置的域名。

如何做到这一点?

原始json:

{
  "key1":"value1",
  "key2":"value2"
}

想要的json:

{
  "key1":"value1",
  "key2":"value2",
  "ssl_certificate": "/etc/letsencrypt/live/somesite.com/fullchain.pem",
  "ssl_certificate_key": "/etc/letsencrypt/live/somesite.com/fullchain.pem"
}
4

2 回答 2

1

下的字符串构造

我使用八进制表示来嵌套引号和双引号printf

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",
  "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"
}

2b。jq用'--arg选项写得更好:

感谢peak的详细回答

我使用数组来存储带有引号、空格和其他特殊字符的字符串。这更具可读性,因为无需转义行尾(反斜杠)并允许注释:

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"
}

3.内联编辑功能

用于编辑小脚本。我更喜欢使用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选项:

myFunc -r site_config.json test.org
于 2020-10-28T07:47:00.177 回答
1

我无法将位置参数传递到 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 }'
``


于 2020-10-28T08:40:16.577 回答