如何在 bash 中使用带有嵌入引号的位置参数?

How to use positional argument with embed quotes in bash?

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

我必须编辑的文件是 json 所以我只需要使用 jq 来编辑它并通过脚本的位置参数将网站名称传递给它,但我不能'获取传递到 json 文本中的位置参数。

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

JSON=`jq '. + { "ssl_certificate": "/etc/letsencrypt/live//fullchain.pem" }' <<< echo site_config.json`
JSON=`jq '. + { "ssl_certificate_key": "/etc/letsencrypt/live//fullchain.pem" }' <<< ${JSON}`
echo -e "$JSON" > site_config.json

其中第二个位置参数(</code>)包含需要在 json 文件中设置的域名。</p> <p>如何做到这一点?</p> <p>原文json:</p> <pre><code>{ "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"
}

1。

下的字符串构造

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

printf -v JSON 'Some "double quoted: 7%s7"' "Any string"
echo "$JSON"
Some "double quoted: 'Any string'"

2。使用 jq,严格回答已编辑的问题:

myFunc() {
    local file="" site="" 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":"Let7s doit1"  }'
    ) 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 选项写得更好:

感谢

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

myFunc() {
    local file="" site=""
    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
    [ "" = "-r" ] && REPLACE=true && shift
    local file="" site=""
    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

I cannot get the positional argument passed into the json text.

一般来说,到目前为止最好的方法是使用 jq 的 --arg and/or --argjson command-line 选项。这是安全的,在当前情况下意味着您只需调用 jq 一次。例如:

< site_config.json \
jq --arg sslc "/etc/letsencrypt/live//fullchain.pem" \
   --arg sslck "/etc/letsencrypt/live//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//fullchain.pem" \
   --arg ssl_certificate_key "/etc/letsencrypt/live//fullchain.pem" '
   . + {$ssl_certificate, $ssl_certificate_key }'
``