Лучший дизайн не потребует , чтобы вы знали, сколько уровней глубины вложения в вашем файле, и определенно не будет вызывать jq
снова и сновав петле!(jq
- это полноценный язык программирования - он может выполнять цикл самостоятельно, и гораздо эффективнее обрабатывать весь файл всего за один вызов jq, а не вызывать его снова и снова с разными фильтрами).
Давайте начнем с конкретного примера ввода:
{
"item0": {
"item0a": {
"item0aA": {
"name": "foo",
"url": "bar"
},
"item0aB": {
"name": "baz",
"url": "qux"
}
}
},
"item1": {
"name": "qux",
"url": "quux"
}
}
Чтобы преобразовать это в сплющенный набор имен / URL-адресов, можно использовать:
jq -r '.. | objects | select(.name? != null) | [ .name, .url ] | @tsv'
который выдаст в качестве вывода:
foo bar
baz qux
qux quux
... который вы можете тривиально перебрать в bash:
while IFS=$'\t' read -r name url; do
echo "Read name $name and url $url"
done < <(jq -r '.. | objects | select(.name? != null) | [ .name, .url ] | @tsv' <json.list)
Разбить, как это работает:
..
- это оператор рекурсивного спуска jq. objects
игнорирует вещи, которые не являются объектами. .name? != null
фильтрует только те объекты, которые имеют имена.(Подобным же образом можно фильтровать только те объекты, которые имеют URL-адреса одинаково). @tsv
помещает выходные данные в разделенную табуляцией форму значения. IFS=$'\t' read -r name url
считывает строку ввода впеременные name
и url
с вкладкой, разделяющей их.