如何在jq中将JSON对象转换为key=value格式?

qltillow  于 2023-08-08  发布在  其他
关注(0)|答案(6)|浏览(110)

在jq中,如何将JSON转换为带有key=value的字符串?
发件人:

{
    "var": 1,
    "foo": "bar",
    "x": "test"
}

字符串
收件人:

var=1
foo=bar
x=test

djmepvbi

djmepvbi1#

您可以尝试:

jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' test.json

字符串
下面是一个演示:

$ cat test.json
{
    "var": 1,
    "foo": "bar",
    "x": "test"
}
$ jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]' test.json
foo=bar
var=1
x=test

a9wyjsp7

a9wyjsp72#

有没有什么方法可以递归地做这个?
下面是一个函数,它可以做你想要的:

# Denote the input of recursively_reduce(f) by $in.
# Let f be a filter such that for any object o, (o|f) is an array.
# If $in is an object, then return $in|f;
# if $in is a scalar, then return [];
# otherwise, collect the results of applying recursively_reduce(f)
# to each item in $in.
def recursively_reduce(f):
  if type == "object" then f
  elif type == "array" then map( recursively_reduce(f) ) | add
  else []
  end;

字符串
示例:发出键=值对

def kv: to_entries | map("\(.key)=\(.value)");

[ {"a":1}, [[{"b":2, "c": 3}]] ] | recursively_reduce(kv)
#=> ["a=1","b=2","c=3"]


更新:在jq 1.5发布后,walk/1作为jq定义的内置添加。它可以与上述定义的kv一起使用,例如具体如下:

walk(if type == "object" then kv else . end)


使用上述输入,结果将是:
[[“a=1”],[[“B=2”,“c=3”]
要“平坦化”输出,可以使用flatten/0。下面是一个完整的例子:

jq -cr 'def kv: to_entries | map("\(.key)=\(.value)");
        walk(if type == "object" then kv else . end) | flatten[]'


输入:

[ {"a":1}, [[{"b":2, "c": 3}]] ]


输出量:

a=1
b=2
c=3

b1zrtrql

b1zrtrql3#

顺便说一句,基于@aioobe的出色回答。如果你需要所有的键都是大写的,你可以使用ascii_upcase来修改他的例子:

jq -r 'to_entries|map("\(.key|ascii_upcase)=\(.value|tostring)")|.[]'

字符串

示例

我有一个类似于你的场景,但在创建访问AWS的环境变量时,我希望将所有键都大写。

$ okta-credential_process arn:aws:iam::1234567890123:role/myRole | \
     jq -r 'to_entries|map("\(.key|ascii_upcase)=\(.value|tostring)")|.[]'
EXPIRATION=2019-08-30T16:46:55.307014Z
VERSION=1
SESSIONTOKEN=ABcdEFghIJ....
ACCESSKEYID=ABCDEFGHIJ.....
SECRETACCESSKEY=AbCdEfGhI.....

参考资料

yk9xbfzb

yk9xbfzb4#

没有jq,我可以使用grepsed导出json中的每一个项目,但这只适用于简单的情况,我们有键/值对

for keyval in $(grep -E '": [^\{]' fileName.json | sed -e 's/: /=/' -e "s/\(\,\)$//"); do
    echo "$keyval"
done

字符串
下面是一个响应示例:

❯ for keyval in $(grep -E '": [^\{]' config.dev.json | sed -e 's/: /=/' -e "s/\(\,\)$//"); do
    echo "$keyval"       
done
"env"="dev"
"memory"=128
"role"=""
"region"="us-east-1"

yk9xbfzb

yk9xbfzb5#

要在aaiobe’s answer的基础上添加,这里有一些事情可以使它更安全/更灵活地用途:

  • null安全性的问号
  • 支持一级嵌套数组
  • jsn_修复命名空间的结果变量,以避免他们覆盖你的正常变量
$ cat nil.jsn
null
$ jq -r 'to_entries? | map("set -A jsn_\(.key|@sh) -- \(.value|@sh)") | .[]' <nil.jsn
$ cat test.jsn
{
  "var": 1,
  "foo": [
    "bar",
    "baz",
    "space test"
  ],
  "x": "test"
}
$ jq -r 'to_entries? | map("set -A jsn_\(.key|@sh) -- \(.value|@sh)") | .[]' <nil.jsn
$ jq -r 'to_entries? | map("set -A jsn_\(.key|@sh) -- \(.value|@sh)") | .[]' <test.jsn
set -A jsn_'var' -- 1
set -A jsn_'foo' -- 'bar' 'baz' 'space test'
set -A jsn_'x' -- 'test'

字符串
上面的输出是Korn Shell数组(对于mksh和AT&T ksh)。如果你更喜欢/需要GNU bash风格的数组(也被许多其他最近的shell版本支持),用途:

$ jq -r 'to_entries? | map("jsn_\(.key | @sh)=(\(.value | @sh))") | .[]' <nil.jsn
$ jq -r 'to_entries? | map("jsn_\(.key | @sh)=(\(.value | @sh))") | .[]' <test.jsn
jsn_'var'=(1)
jsn_'foo'=('bar' 'baz' 'space test')
jsn_'x'=('test')


在所有后续的例子中,我将使用Korn Shell变体,但应用上述两个变体之间的差异将适用于它们。
在这两种情况下,你都得到了数组,但是解引用数组本身与解引用它的元素#0是一样的,所以即使对于单个值,这也是安全的:

$ eval "$(jq -r 'to_entries? | map("set -A jsn_\(.key|@sh) -- \(.value|@sh)") | .[]' <test.jsn)"
$ echo $jsn_x
test
$ echo $jsn_foo = ${jsn_foo[0]} but not ${jsn_foo[1]}
bar = bar but not baz


但也有一个缺点:只为sh编写的脚本没有数组,因此您需要以bashksh88ksh93mkshzsh(可能还有其他)或它们的公共子集(所有这些都支持[[ … ]];除了ksh88之外,所有的都应该支持GNU bash风格的数组)。
两个进一步的改进:

  • 手动null处理(见下文)
  • 从白名单中筛选顶级密钥
$ jq -r 'if . == null then
>         null
> else
>         to_entries | map(
>                 select(IN(.key;
>                         "foo", "val", "var"
>                 )) | "set -A jsn_\(.key | @sh) -- \(.value | @sh)"
>         ) | .[]
> end' <nil.jsn
null
$ jq -r 'if . == null then
>         null
> else
>         to_entries | map(
>                 select(IN(.key;
>                         "foo", "val", "var"
>                 )) | "set -A jsn_\(.key | @sh) -- \(.value | @sh)"
>         ) | .[]
> end' <test.jsn
set -A jsn_'var' -- 1
set -A jsn_'foo' -- 'bar' 'baz' 'space test'


在本例中,只允许使用密钥fooval(此处不存在)和var。这可以用于例如过滤掉其值不是简单值或简单值的一维JSONArray的键,因此结果是安全的¹。
你可以用这个,例如。如下所示:

set -o pipefail
if ! vars=$(curl "${curlopts[@]}" "$url" | jq -r '
        if . == null then
                null
        else
                to_entries | map(
                        select(IN(.key;
                                "foo", "val", "var"
                        )) | "set -A jsn_\(.key | @sh) -- \(.value | @sh)"
                ) | .[]
        end
    '); then
        echo >&2 "E: no API response"
        exit 1
fi
if [[ $vars = null ]]; then
        echo >&2 "E: empty API response"
        exit 1
fi
eval "$vars"
echo "I: API response: var=$jsn_var"
for x in "${jsn_foo[@]}"; do
        echo "N: got foo '$x'"
done


①虽然jq会抛出错误,除非使用问号,但如果确实存在多维数组或其他诡计,则失败模式就不那么好了:

$ cat test.jsn 
{
  "foo": [
    [
      "bar",
      "baz"
    ],
    "space test"
  ],
  "var": 1,
  "x": "test"
}
$ jq -r 'to_entries? | map("set -A jsn_\(.key|@sh) -- \(.value|@sh)") | .[]' <test.jsn
$ echo $?
0
$ jq -r 'to_entries | map("set -A jsn_\(.key|@sh) -- \(.value|@sh)") | .[]' <test.jsn 
jq: error (at <stdin>:11): array (["bar","baz"]) can not be escaped for shell
$ echo $?
5
$ jq -r 'if . == null then
>         null
> else
>         to_entries | map(
>                 select(IN(.key;
>                         "foo", "val", "var"
>                 )) | "set -A jsn_\(.key | @sh) -- \(.value | @sh)"
>         ) | .[]
> end' <test.jsn
jq: error (at <stdin>:11): array (["bar","baz"]) can not be escaped for shell
$ echo $?
5


如果你不知道你的JSON是否正常,一定要测试一下。见鬼,测试一下,总是这样; catch jq错误退出代码。注意上面例子中的set -o pipefail,如果shell支持(最新的shell支持),如果cURL或jq失败(或者两者都失败),整个命令替换将失败;否则,你必须将cURL输出重定向到一个临时文件,检查curl的errorlevel,然后在命令替换中对临时文件运行jq并检查其退出状态(如果你希望在错误消息中区分它们,你仍然必须精确地这样做)。

wixjitnu

wixjitnu6#

这里有一个紧凑的解决方案:第一个月

$ echo '{"var": 1, "foo": "bar", "x": "test"}' | \
jq -r 'to_entries[]|join("=")'
var=1
foo=bar
x=test

字符串

相关问题