Как преобразовать объект JSON в key = value в jq?

В jq, как я могу преобразовать JSON в строку с key=value?

From:

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

To:

var=1
foo=bar
x=test

Ответы

Ответ 1

Вы можете попробовать:

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

Ответ 2

Есть ли способ сделать это рекурсивно?

Вот функция, которая может делать то, что вы хотите:

# 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;

Пример: emit key = value пары

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


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

UPDATE: после выхода jq 1.5, walk/1 был добавлен как встроенный jq-встроенный. Его можно использовать с вышеописанным kv, например. следующим образом:

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

С приведенным выше результатом результат будет:

[[ "= 1" ], [[[ "Ь = 2", "с = 3" ]]]]

Чтобы "сгладить" выход, можно использовать flatten/0. Вот полный пример:

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

Input:

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

Вывод:

a=1
b=2
c=3

Ответ 3

Я знаю, что jq очень популярен здесь, но могу ли я посоветовать взглянуть на Xidel?
Xidel - это анализатор HTML/XML/JSON (с использованием CSS, XPath, XQuery, JSONiq и шаблонных шаблонов), но он может делать гораздо больше. Это работа гения, и если вы спросите меня настоящий швейцарский нож в этой категории!

Для отдельных объектов это довольно просто:

$ echo '{"var":1,"foo":"bar","x":"test"}' | \
xidel -s - -e '$json()'
var
foo
x
$ echo '{"var":1,"foo":"bar","x":"test"}' | \
xidel -s - -e '
  for $x in $json()
  return
  concat(
    $x,
    "=",
    $json($x)
  )
'
var=1
foo=bar
x=test

Для более продвинутых JSON проще всего сгладить весь JSON (хотя декларация пространства имен необходима!):

$ echo '[{"a":1},[[{"b":2,"c":3}]]]' | \
xidel -s - --xmlns:jnlib="http://jsoniq.org/function-library" -e 'jnlib:flatten($json)'
{
  "a": 1
}
{
  "b": 2,
  "c": 3
}
$ echo '[{"a":1},[[{"b":2,"c":3}]]]' | \
xidel -s - --xmlns:jnlib="http://jsoniq.org/function-library" -e '
  let $a:=jnlib:flatten($json) return
  $a() ! concat(
    .,
    "=",
    $a(.)
  )
'

#or

$ echo '[{"a":1},[[{"b":2,"c":3}]]]' | \
xidel -s - --xmlns:jnlib="http://jsoniq.org/function-library" --xquery '
  let $a:=jnlib:flatten($json)
  for $x in $a()
  return
  concat(
    $x,
    "=",
    $a($x)
  )
'
a=1
b=2
c=3

Ответ 4

Кстати, построение @aioobe отличный ответ. Если вам нужно, чтобы все клавиши были в верхнем регистре, вы можете использовать ascii_upcase, изменив его пример:

jq -r 'to_entries|map("\(.key|ascii_upcase)=\(.value|tostring)")|.[]'
Пример

Example

У меня был сценарий, похожий на ваш, но я хотел прописать все ключи в верхнем регистре при создании переменных среды для доступа к 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.....

Ссылки