Używanie jq do parsowania i wyświetlania wielu pól w jsonie szeregowo

237

Mam tego Jsona

{
    "users": [
        {
            "first": "Stevie",
            "last": "Wonder"
        },
        {
            "first": "Michael",
            "last": "Jackson"
        }
    ]
}

Za pomocą jq chciałbym wyświetlać imię i nazwisko szeregowo. Tak jak -

Stevie Wonder
Michael Jackson

Tak daleko zaszedłem -

jq '.users[].first, .users[].last'

Ale wyświetla się

"Stevie"
"Michael"
"Wonder"
"Jackson"

Zwróć uwagę na następujące -

  1. Podwójne cytaty, których nie chcę.
  2. Zwrot karetki, którego nie chcę.
  3. Jest pomieszane. Moje zapytanie wyświetla najpierw wszystkie imiona, a następnie wszystkie nazwiska. Chcę jednak pierwszej, ostatniej pary.
San
źródło

Odpowiedzi:

338

Polecam użycie interpolacji ciągów:

jq '.users[] | "\(.first) \(.last)"'

odniesienie

Eric Hartford
źródło
13
jest to o wiele lepsze, jeśli dane są liczbami
ozOli
203

Możesz użyć dodawania do łączenia ciągów.

Ciągi są dodawane przez połączenie w większy ciąg.

jq '.users[] | .first + " " + .last'

Powyższe prace przy obu firsti lastsą ciągiem. Jeśli wyodrębniasz różne typy danych (numer i ciąg), musimy przekonwertować na równoważne typy. Odnosząc się do rozwiązania tego pytania . Na przykład.

jq '.users[] | .first + " " + (.number|tostring)'
Abraham
źródło
41
Aby wyeliminować znaki cudzysłowu JSON, wywołaj jq z opcją -r, np. Jq -r '.users [] | .pierwszy + „” + .last ”
szczyt
4
+1, ale w moim przypadku użycia próbuję sformatować dwie liczby w tym samym wierszu. To podejście zawodzi, ponieważ nie można go dodać " "do liczby. Odpowiedź Erica daje lepszy wynik w tej sprawie.
Synesso,
9
@Synesso: (.numA|tostring) + " " + (.numB|tostring)powinien działać. Lub interpolacja użycie ciąg zamiast: "\(.numA) \(.numB)".
LS
Kiedy to zrobiłem jq '.users[] | .first + " " + .last', działało to bardzo dobrze, ale spowodowało nową linię między wartością .firsta .last. Zmieniłem " "się "@", a następnie zrobił sed 's/@/ /g'na wyjściu uzyskać „John Smith” jako wyjście. Coś w tym stylu:jq '.users[] | .first + "@" + .last' | sed 's/@/ /g'
Bloodysock
33
jq '.users[]|.first,.last' | paste - -
optman
źródło
14

Podczas gdy obie powyższe odpowiedzi działają dobrze, jeśli klucz, wartość są łańcuchami, miałem sytuację, aby dołączyć ciąg i liczbę całkowitą (błędy JQ przy użyciu powyższych wyrażeń)

Wymagania: Aby utworzyć adres URL poniżej JSON

pradeep@seleniumframework>curl http://192.168.99.103:8500/v1/catalog/service/apache-443 | jq .[0]
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   251  100   251    0     0   155k      0 --:--:-- --:--:-- --:--:--  245k
{
  "Node": "myconsul",
  "Address": "192.168.99.103",
  "ServiceID": "4ce41e90ede4:compassionate_wozniak:443",
  "ServiceName": "apache-443",
  "ServiceTags": [],
  "ServiceAddress": "",
  "ServicePort": 1443,
  "ServiceEnableTagOverride": false,
  "CreateIndex": 45,
  "ModifyIndex": 45
}

Rozwiązanie:

curl http://192.168.99.103:8500/v1/catalog/service/apache-443 |
jq '.[0] | "http://" + .Address + ":" + "\(.ServicePort)"'
machzqcq
źródło
zwróć uwagę, że ucieczka od nawiasu zamykającego nie jest potrzebna i spowodowałaby błąd.
nymo
2
@nymo: To nie ucieka. \(...)jest interpolacją ciągów. Tutaj zamienia liczbę .ServicePortw ciąg znaków. Zamiast +znaków można zastosować interpolację, aby skrócić to rozwiązanie.
LS
12

Spowoduje to utworzenie tablicy nazw

> jq '[ .users[] | (.first + " " + .last) ]' ~/test.json

[
  "Stevie Wonder",
  "Michael Jackson"
]
TinyRoy
źródło
4

Byłem bardzo blisko tego, co chciałem, robiąc coś takiego

cat my.json | jq '.my.prefix[] | .primary_key + ":", (.sub.prefix[] | "    - " + .sub_key)' | tr -d '"' 

Dane wyjściowe są na tyle blisko, że yaml zwykle pozwala bez problemu importować je do innych narzędzi. (Nadal szukam sposobu, aby wyeksportować podzbiór wejściowego pliku json)

ThorSummoner
źródło
1
Ten rodzaj działa w moim przypadku, po prostu upuść | tr -d '”na końcu i dodaj opcję -r do jq.
user842479
4

moje podejście będzie (twój przykład JSON nie jest dobrze sformułowany .. zgadnij, że to tylko próbka)

jq '.Front[] | [.Name,.Out,.In,.Groups] | join("|")'  front.json  > output.txt

zwraca coś takiego

"new.domain.com-80|8.8.8.8|192.168.2.2:80|192.168.3.29:80 192.168.3.30:80"
"new.domain.com -443|8.8.8.8|192.168.2.2:443|192.168.3.29:443 192.168.3.30:443"

i grep wyjście z wyrażeniem regularnym.

Ganesh Chandrasekaran
źródło