проаналізуйте одне поле з масиву JSON в масив bash


14

У мене є вихід JSON, який містить перелік об'єктів, що зберігаються у змінній. (Я, можливо, не фразую це право)

[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

Мені потрібні всі значення для item2 в масиві для bash-сценарію, який запускається на ubuntu 14.04.1.

Я знайшов купу способів отримати весь результат у масив, але не лише потрібні мені елементи

Відповіді:


18

Використання :

$ cat json
[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

КОД:

arr=( $(jq -r '.[].item2' json) )
printf '%s\n' "${arr[@]}"

ВИХІД:

value2
value2_2

Чи можна це зробити зі змінної замість файлу? Я намагаюся уникати зайвого доступу до файлової системи, якщо він мені не потрібен. Після того, як я витягну цей масив, я закінчую з виходом json.
JpaytonWPD

1
Ви щось пробували?
Жиль Кінот

2
jq . <<< "$json"це оболонка (баш), пов’язана з нею,jq
нехарактерно

1
Пропущені круглі дужки:arr=( $(...) )
Жиль Кінот

4
Відмінна jqкоманда, але, будь ласка, не розбирайте вихід команди в масив із arr=( $(...) )(хоча це трапляється працювати із зразком введення): він не працює за призначенням із вбудованим або ведучим / заднім пробілом і може призвести до випадкового глобалізації.
mklement0

5

Насправді насправді баггі:

# BAD: Output line of * is replaced with list of local files; can't deal with whitespace
arr=( $( curl -k "$url" | jq -r '.[].item2' ) )

Замість цього використовуйте:

# GOOD (with bash 4.x+), but can't detect failure
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )

... або, ще краще ...

# GOOD (with bash 3.x+), *and* has nonzero status if curl or jq fails
IFS=$'\n' read -r -d '' -a arr \
  < <(set -o pipefail; curl --fail -k "$url" | jq -r '.[].item2' && printf '\0')

2

Завдяки Sputnick я дійшов до цього:

arr=( $(curl -k https://localhost/api | jq -r '.[].item2') )

У мене JSON - це вихід з API. Все, що мені потрібно було зробити, хоче видалити аргумент файлу і |передати висновок curl в jq. Чудово працює і заощадив кілька кроків.


Цей код насправді трохи баггі. Подивіться, що станеться, якщо у вас є елемент результату *- він буде замінений на список файлів у вашому поточному каталозі.
Чарльз Даффі,

1
Аналогічно, item2значення з пробілом у ньому стане більш ніж одним елементом масиву.
Чарльз Даффі

0

як просту альтернативу, подивіться на jtcінструмент (на https://github.com/ldn-softdev/jtc ), щоб досягти того ж (як у прикладі jq):

bash $ arr=( $(jtc -w '<item2>l+0' file.json) )
bash $ printf '%s\n' "${arr[@]}"
"value2"
"value2_2"
bash $ 

пояснення на -wваріант: кутові дужки <...>вказують пошук у всьому json, суфікс lвказує на пошук міток, а не значень, +0інструктаж для пошуку всіх подій (а не лише першого).


Та сама помилка, як і всі arr=( $(jq ...) )відповіді, якщо вміст розбивається на рядки та розширюється на глобальний для заповнення масиву - значить пробіли (а не лише нові рядки) створюють нові елементи, а елементи, схожі на вираз глобуса, замінюються файлами, які вирази збігів.
Чарльз Даффі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.