Как добавить массив json с помощью jq+shell в цикле?

Я могу создать объект json с массивом, используя jq, как это

echo '{"input":{"names":[]}}' | jq --arg val "alice" '.input.names[0] += $val'| jq --arg val "bob" '.input.names[1] += $val'

который дает

{
  "input": {
    "names": [
      "alice",
      "bob"
    ]
  }
}

Теперь я хочу воссоздать это в сценарии оболочки, где «имена» берутся из массива оболочки.

#!/bin/sh

names=( alice bob )
                 
ITER=0
for i in "${names[@]}"
do                  
    echo '{"input":{"names":[]}}' |  jq --arg val "$i" '.input.names[$ITER] += $val'
    echo ${I} ${ITER}                                                               
    ITER=$(expr $ITER + 1)                                                          
done  

но я сталкиваюсь

jq: error: $ITER is not defined at <top-level>, line 1:
.input.names[$ITER] += $val             
jq: 1 compile error
0
jq: error: $ITER is not defined at <top-level>, line 1:
.input.names[$ITER] += $val             
jq: 1 compile error
1

Либо присвойте (=, а не +=) индексу массива jq --arg val "alice" '.input.names[0] = $val', либо добавьте (+=) к массиву, не используя индекс и скобки массива в правой части: jq --arg val "alice" '.input.names += [$val]'.

pmf 12.05.2022 14:52

я пытался echo '{"input":{"names":[]}}' | jq --arg val "$i" '.input.names += [$val]' но он просто создает два разных объекта

SAS 12.05.2022 14:58

Поскольку вы не фиксируете выходные данные шага итерации, вы теряете выходные данные одного вызова и начинаете все сначала в следующем. Я добавил решение bash, реализующее ваш цикл for при захвате выходных данных.

pmf 12.05.2022 15:09
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
0
3
34
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете избавиться от оболочки и использовать один вызов jq:

names=( alice bob )
jq -n --arg names "${names[*]}" '{"input": {"names": ($names / " ") } }'

или

name=( alice bob )
printf '%s\0' "${names[@]}" |
jq -sR '(. / "\u0000") as $names | { "input": { "names": $names } }'

Если я заменю \0 в варианте printf на | (и, конечно, \u0000 тоже), то массив будет ["alice","bob",""]. Так почему же это не так с \0?

A.H. 15.05.2022 11:15

Я не знаю причину. Это может быть давняя ошибка, что \u0000 обрабатывается таким образом, хотя это удобно

Fravadona 15.05.2022 11:20

Вы не фиксируете вывод шага итерации, поэтому вы теряете вывод вызова jq и начинаете все сначала на следующем шаге итерации.

Вот решение bash, которое захватывает вывод с помощью $(...) и предоставляет его для следующего использования с помощью <<<. (Обратите внимание, что есть лучшие способы решить эту проблему, например, без цикла, но доказав, что jq все элементы должны быть добавлены одновременно.)

json='{"input":{"names":[]}}'

for i in alice bob
do json = "$(jq --arg val "$i" '.input.names += [$val]' <<< "$json")"
done

echo "$json"
{
  "input": {
    "names": [
      "alice",
      "bob"
    ]
  }
}

да... это тоже сработало... спасибо

SAS 12.05.2022 16:44

Другие вопросы по теме