parsuje jedno pole z tablicy JSON w tablicę bash


14

Mam wyjście JSON, które zawiera listę obiektów przechowywanych w zmiennej. (Nie mogę frazować tego prawa)

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

Potrzebuję wszystkich wartości dla item2 w tablicy, aby skrypt bash mógł być uruchomiony na Ubuntu 14.04.1.

Znalazłem wiele sposobów na umieszczenie całego wyniku w tablicy, ale nie tylko potrzebnych mi przedmiotów

Odpowiedzi:


18

Za pomocą :

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

KOD:

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

WYNIK:

value2
value2_2

Czy można to zrobić ze zmiennej zamiast z pliku? Staram się unikać nadmiernego dostępu do systemu plików, jeśli go nie potrzebuję. Po wyciągnięciu tej tablicy skończę z wyjściem json.
JpaytonWPD,

1
Próbowałeś czegoś
Gilles Quenot

2
jq . <<< "$json"jest związany z powłoką (bash), niespecyficzny dlajq
Gilles Quenot

1
Brakujące nawiasy:arr=( $(...) )
Gilles Quenot

4
Świetna jqkomenda, ale proszę nie analizować danych wyjściowych komendy w tablicy z arr=( $(...) )(chociaż zdarza się, że działa z przykładowymi danymi wejściowymi): nie działa zgodnie z przeznaczeniem z osadzonymi lub wiodącymi / końcowymi białymi spacjami i może spowodować przypadkowe globbing.
mklement0

5

Następujące błędy są w rzeczywistości:

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

Zamiast tego użyj:

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

... lub jeszcze lepiej ...

# 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

Dzięki sputnick doszedłem do tego:

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

JSON, który mam, jest wyjściem z API. Wszystko, co musiałem zrobić, to usunąć argument pliku i przesłać |wyjście curl do jq. Działa świetnie i zapisał kilka kroków.


Ten kod jest właściwie trochę błędny. Zobacz, co się stanie, jeśli masz element wynikowy *- zostanie on zastąpiony listą plików w bieżącym katalogu.
Charles Duffy,

1
Podobnie item2wartość z białymi znakami stałaby się więcej niż jednym elementem tablicy.
Charles Duffy,

0

jako łatwą alternatywę, spójrz na jtcnarzędzie (na https://github.com/ldn-softdev/jtc ), aby osiągnąć to samo (jak w przykładzie jq):

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

wyjaśnienie -wopcji: nawiasy kątowe <...>określają wyszukiwanie całego JSON, sufiks lnakazuje wyszukiwanie etykiet zamiast wartości, +0instruuje, aby znaleźć wszystkie wystąpienia (zamiast tylko pierwszego).


Ten sam błąd co wszystkie arr=( $(jq ...) )odpowiedzi, o ile treść jest dzielona na ciągi znaków i rozwijana globalnie, aby zapełnić tablicę - co oznacza, że ​​spacje (nie tylko nowe linie) tworzą nowe elementy, a elementy, które wyglądają jak wyrażenie globalne, są zastępowane plikami, które dopasowania do wyrażenia.
Charles Duffy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.