jq & bash: сделать массив JSON из переменной

Я использую jq для формирования JSON в bash из значений переменных.

Получил, как сделать простые переменные

$ VAR="one two three"
$ jq -n "{var:\"$VAR\"}"
{
  "var": "one two three"
}

Но он не может создавать массивы. у меня есть

$ echo $ARR
one
two
three

и хотите получить что-то вроде

{
  "arr": ["one", "two", "three"]
}

Мне только удается получить искаженный вывод, как

$ jq -n "{arr: [\"$ARR\"]}"
{
  "arr": [
    "one\ntwo\nthree"
  ]
}

Как правильно сформировать массив JSON? Может ли jq это сделать?

EDIT: вопрос был задан, когда был только jq 1.3. Теперь, в jq 1.4, можно сделать то, о чем я просил, например, @JeffMercado и @peak, предложили им возвышение. Однако не отменит принятие ответа @jbr.

Ответы

Ответ 1

jq делает именно то, что вы говорите ему. jq - не программа для генерации JSON, а инструмент для его запроса. То, что вы делаете с коммутатором -n просто использует его как красивый принтер. Поэтому, если вы хотите, чтобы он печатал объект с массивом, содержащим "один", "два", "три", вы должны его сгенерировать.

VAR="one two three"
VAR=$(echo $VAR | sed -e 's/\(\w*\)/,"\1"/g' | cut -d , -f 2-)
echo "{var: [$VAR]}"

Обновить

Как упоминает Брайан и другие ниже, действительно возможно генерировать JSON с jq, а с версии 1.4 можно даже делать то, что OP задает напрямую, см., Например, ответ Джеффа.

Ответ 2

В jq 1.3 и выше вы можете использовать --arg VARIABLE VALUE командной строки --arg VARIABLE VALUE:

jq -n --arg v "$VAR" '{"foo": $v}'

Т.е., --arg устанавливает переменную в заданное значение, поэтому вы можете использовать $varname в вашей jq-программе, и теперь вам не нужно использовать интерполяцию переменных оболочки в вашу jq-программу.

EDIT: из jq 1.5 и выше вы можете использовать --arg json для передачи в массиве напрямую, например

jq -n --argjson v '[1,2,3]' '{"foo": $v}'

Ответ 3

Если у вас есть переменная загружена, вы должны использовать split фильтр, чтобы разделить эту строку в массив.

$ jq -n --arg inarr "${ARR}" '{ arr: $inarr | split("\n") }'

Ответ 4

В оригинальной публикации в этой теме упоминается VAR = "один два три". Для такой переменной очень простое решение в jq 1.4 выглядит следующим образом:

$ jq -n -c -M --arg s "$VAR" '{var: ($s|split(" "))}'
{"var":["one","two","three"]}

(Это предполагает оболочку Linux или Mac или аналогичную, и работает с jq 1.4.)

Если символ разделителя является символом новой строки, тогда рассмотрим этот машинописный текст:

$ s=$(printf "a\nb\nc\n")
$ jq -n -c -M --arg var "$s" '{"var": ($var|split("\n"))}'
{"var":["a","b","c"]}

Обратите внимание, что строка JSON для символа новой строки - "\n" (не "\\n").

Третий случай представляет интерес, когда VAR является массивом bash. В этом случае может быть приемлемым передать элементы, используя "$ {VAR [@]}", но в целом следует помнить, что значение "--arg name name" предназначено только для передачи в строках.

В jq> 1.4 экспортируемые переменные оболочки могут быть переданы с использованием объекта env, как описано на странице справочника онлайн jq.

Ответ 5

Сначала вы должны использовать -R для чтения необработанных строк, а затем вам нужно сбросить все значения с помощью -s:

$ echo -e "one\ntwo\nthree" | jq -R . | jq -s '{"arr": .}'
{
  "arr": [
    "one",
    "two",
    "three"
  ]
}

Ответ 6

Вы можете использовать этот синтаксис:

jq --arg keyName "MyVal" '.[]."\($keyName)"[] ./JSONFile.js

для входных данных, таких как

[{"MyVal":"Value1","MyVal":Value2,"NotMyVal":"Value3"}];

для получения анализируемых данных из JSON с переменными.

В этом примере будет напечатан:

"Value1"
"Value2"