Во-первых, давайте предположим, что у нас есть функция для выполнения одного вызова API.
do_api () {
key=$1
curl $HTTP://$IP:$PORT/api # Presumably, key is needed here somewhere
}
Я также предполагаю, что предполагаемый вывод - это объект JSON, имеющий как минимум два поля, data1
и data2
.Теперь мы можем написать простой конвейер с тремя этапами:
- Чтение ключей из
$CONFIG
- Выполнение вызова API для каждого ключа
- Создание требуемого выводаиз объединенного вывода всех вызовов API.
Это не слишком сложно:
jq -r '.servers | keys[]' | # stage 1
while read key; do do_api "$key"; done | # stage 2
jq -s 'to_entries |
map({key: "server(\.key+1)",
value: {data1: .value.data1,
data2: .value.data2}
}) |
{success: "OK", servers: from_entries}' # stage 3
do_api
не должно ничего выводить для определенного ключа curl
, но не удается, ноВы можете изменить его, чтобы получить какие-то данные по умолчанию, если хотите:
do_api () {
key=$1
curl --fail ... || jq -n '{data1: null, data2: null}'
}
jq -s 'to_entries'
принимает данные типа
{ "data1": ..., "data2": ... }
{ "data1": ..., "data2": ... }
(что мы и ожидаем отcurl
) и выдает в качестве вывода
[ { "key": 0, "value": { "data1": ..., "data2": ... } },
{ "key": 1, "value": { "data1": ..., "data2": ... } }
]
Фильтр map(...)
берет предыдущий массив и создает ключи и значения, которые мы хотим добавить к объекту servers
в конечном результате, которыйсозданный путем вызова from_entries
.
Вот полный пример.tmp.json
содержит смоделированный вывод do_api
, дополненный дополнительным полем data3
, которое будет отфильтровано из окончательного вывода.
$ cat tmp.json
{
"data1": "foo",
"data2": "bar",
"data3": "baz"
}
{
"data1": "hello",
"data2": "world",
"data3": "bye"
}
$ jq -s 'to_entries | map({key: "server\(.key+1)", value: {data1: .value.data1, data2: .value.data2}}) | {success: "OK", servers: from_entries}' tmp.json
{
"success": "OK",
"servers": {
"server1": {
"data1": "foo",
"data2": "bar"
},
"server2": {
"data1": "hello",
"data2": "world"
}
}
}