如何在bash中使用带引号的位置参数? 2b最好使用jq的{​​{1}}选项:

问题描述

我正在尝试创建一个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。

下的字符串构造

我使用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}}选项:

感谢peak's detailed answer

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

--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) 参数必须用双引号引起来。单引号无效。