0Pricing
DevOps Bootcamp · Lekcja

Filtrowanie i wybieranie JSON za pomocą potoków jq

Nawiguj po zagnieżdżonych obiektach i tablicach za pomocą selektorów jq, potoków oraz filtra select.

Filtrowanie i wybieranie JSON za pomocą potoków jq to bezpłatna lekcja DevOps Bootcamp na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej DevOps Bootcamp, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs DevOps Bootcamp zawiera 4 lekcji w sumie.

Czym jest jq i dlaczego warto go używać?

jq to lekkie, zaawansowane narzędzie wiersza poleceń do analizowania, filtrowania i przekształcania danych JSON. Jest odpowiednikiem sed dla JSON — przekazuje się do niego JSON potokiem i otrzymuje z powrotem uporządkowane dane wyjściowe.

  • Jest preinstalowane w większości dystrybucji Linuksa lub dostępne za pomocą apt install jq / brew install jq
  • Bezproblemowo działa w potokach powłoki wraz z curl, cat i innymi narzędziami
  • Obsługuje filtrowanie, mapowanie, redukcję i konwersję formatów

Podstawowe wywołanie ma postać: jq '<filter>' file.json albo jest używane w potoku jako cat file.json | jq '<filter>'. Filtr . (kropka) jest tożsamościowy — wyświetla cały dokument w czytelnie sformatowanej postaci.

# Pretty-print a JSON file
jq '.' data.json

# Or pipe from curl
curl -s https://api.github.com/users/torvalds | jq '.'

Wybieranie pól obiektu za pomocą notacji kropkowej

Aby uzyskać dostęp do pola w obiekcie JSON, należy użyć notacji kropkowej: .fieldName. Selektory można łączyć, aby poruszać się po zagnieżdżonych obiektach.

  • .name — pole najwyższego poziomu
  • .address.city — pole zagnieżdżone
  • ."field-with-dash" — pola ze znakami specjalnymi wymagają cudzysłowów

Jeśli pole nie istnieje, jq zwraca null zamiast zgłaszać błąd. Dzięki temu można bezpiecznie używać go w skryptach bez dodatkowego sprawdzania wartości null dla pól opcjonalnych.

# Given: {"name":"Alice","address":{"city":"Berlin","zip":"10115"}}
echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.name'
# Output: "Alice"

echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.address.city'
# Output: "Berlin"

Dostęp do elementów tablicy i iterowanie

Dostęp do tablic JSON uzyskuje się za pomocą notacji nawiasowej. jq używa indeksowania od zera.

  • .items[0] — pierwszy element
  • .items[-1] — ostatni element
  • .items[1:3] — wycinek (od indeksu 1 do indeksu 3, bez indeksu 3)
  • .items[] — rozwija tablicę: wyświetla każdy element jako osobną wartość (jest to iterator)

Iterator [] ma podstawowe znaczenie w potokach jq — umożliwia niezależne zastosowanie kolejnych filtrów do każdego elementu.

# Given an array of users
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[0]'
# Output: {"name":"Alice"}

# Iterate all elements and extract .name from each
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[].name'
# Output:
# "Alice"
# "Bob"
# "Carol"

Budowanie potoków jq za pomocą operatora potoku

Podobnie jak powłokowy potok |, jq ma własny wewnętrzny operator potoku. Przekazuje on dane wyjściowe jednego filtra jako dane wejściowe następnego.

  • jq '.users[] | .name' — iteruje po użytkownikach, a następnie pobiera nazwę każdego z nich
  • jq '.data | .items[] | .id' — przechodzi do danych, rozwija tablicę items, a następnie pobiera identyfikator

Potoki wewnątrz wyrażenia jq pozwalają budować złożone przekształcenia krok po kroku. Każdy etap otrzymuje wszystko, co wygenerował poprzedni etap — w tym wiele wartości pochodzących z iteratora.

Najważniejsza zasada: gdy iterator generuje N wartości, każdy filtr następujący po nim jest uruchamiany N razy, po jednym razie dla każdej wartości.

# Nested pipeline: navigate -> iterate -> extract
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .name'
# Output:
# "Alice"
# "Bob"

# Chain more stages
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .age'
# Output:
# 30
# 25

Filtrowanie za pomocą select()

Filtr select(condition) przepuszcza wartość tylko wtedy, gdy warunek jest prawdziwy; w przeciwnym razie nie generuje żadnych danych wyjściowych. Jest odpowiednikiem grep lub klauzuli WHERE w SQL.

  • select(.age > 18) — zachowuje obiekty, w których wiek jest większy niż 18
  • select(.status == "active") — sprawdza równość
  • select(.name | startswith("A")) — zagnieżdżony test ciągu znaków

Połącz select z iteratorem, aby filtrować tablice: .items[] | select(.active) wyświetla wyłącznie elementy, dla których .active ma wartość prawdziwą.

# Filter array elements by a condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":25}]' \
  | jq '.[] | select(.age >= 18) | .name'
# Output:
# "Alice"
# "Carol"

# Filter by string equality
echo '[{"name":"Alice","role":"admin"},{"name":"Bob","role":"user"}]' \
  | jq '.[] | select(.role == "admin") | .name'
# Output: "Alice"

Odtwarzanie obiektów i tablic za pomocą {} oraz []

jq umożliwia zmianę kształtu danych przez konstruowanie nowych obiektów za pomocą {} oraz nowych tablic za pomocą [].

  • {name: .name, city: .address.city} — wybiera pola i zmienia ich nazwy w nowym obiekcie
  • [.items[] | .id] — zbiera iterowane wartości z powrotem do tablicy
  • Skrócona forma: {name, age} jest równoważna {name: .name, age: .age}

Ujęcie potoku w [...] nazywa się konstrukcją tablicy i jest niezbędne, gdy dane wyjściowe mają być tablicą JSON, a nie strumieniem wartości.

# Reshape: keep only selected fields
echo '[{"id":1,"name":"Alice","password":"secret"},{"id":2,"name":"Bob","password":"secret"}]' \
  | jq '[.[] | {id, name}]'
# Output:
# [
#   {"id": 1, "name": "Alice"},
#   {"id": 2, "name": "Bob"}
# ]

# Collect filtered names into an array
echo '[{"name":"Alice","active":true},{"name":"Bob","active":false}]' \
  | jq '[.[] | select(.active) | .name]'
# Output: ["Alice"]

Praca z zagnieżdżonymi tablicami i rekurencyjne przeszukiwanie

Rzeczywiste dane JSON często są głęboko zagnieżdżone. jq udostępnia dwa narzędzia do nawigowania po głębokiej strukturze:

  • .a.b.c — jawna ścieżka, gdy struktura jest znana
  • .. | .fieldName? — rekurencyjne przeszukiwanie: przechodzi po każdym węźle drzewa i wyświetla wartości w węzłach, w których istnieje dany klucz

Operator ? (try) tłumi błędy, gdy pole nie istnieje w danym węźle. Ma to kluczowe znaczenie podczas rekurencyjnego przeszukiwania niejednorodnych drzew.

Z rekurencyjnego przeszukiwania dużych dokumentów należy korzystać oszczędnie — odwiedza ono każdy węzeł i może działać wolno. Jeśli struktura jest przewidywalna, należy preferować jawne ścieżki.

# Explicit deep path
echo '{"a":{"b":{"c":42}}}' | jq '.a.b.c'
# Output: 42

# Recursive descent: find all "id" values anywhere in the tree
echo '{"users":[{"id":1,"profile":{"id":99}},{"id":2}]}' \
  | jq '.. | .id?'
# Output:
# 1
# 99
# 2

Przykład praktyczny: analizowanie odpowiedzi API curl

Jednym z najczęstszych zastosowań jq jest analizowanie odpowiedzi REST API pobranych za pomocą curl. Połączenie curl -s (trybu cichego) z potokiem jq zapewnia przejrzyste wydobywanie danych, które można łatwo wykorzystać w skryptach.

  • Wyodrębnienie pojedynczej wartości: curl -s URL | jq '.field'
  • Budowanie tabeli podsumowania: iterowanie po tablicy i odtwarzanie obiektów zawierających tylko potrzebne pola
  • Użycie -r (surowe dane wyjściowe) do usunięcia otaczających cudzysłowów z wartości tekstowych — jest to niezbędne podczas przypisywania ich do zmiennych powłoki

Wskazówka: należy zawsze dodawać -r, gdy dane wyjściowe jq będą używane jako zmienna powłoki lub przesyłane do innego polecenia.

#!/usr/bin/env bash
# Fetch GitHub repo info and extract specific fields
REPO="torvalds/linux"
RESPONSE=$(curl -s "https://api.github.com/repos/${REPO}")

# Extract fields
STARS=$(echo "$RESPONSE" | jq -r '.stargazers_count')
LANG=$(echo  "$RESPONSE" | jq -r '.language')
DESC=$(echo  "$RESPONSE" | jq -r '.description')

echo "Stars : $STARS"
echo "Lang  : $LANG"
echo "Desc  : $DESC"

Używanie map() i map_values()

jq udostępnia dwie wygodne funkcje wyższego rzędu do przekształcania kolekcji:

  • map(f) — stosuje filtr f do każdego elementu tablicy i zwraca nową tablicę. Jest równoważne [.[] | f].
  • map_values(f) — stosuje f do każdej wartości w obiekcie lub tablicy, zachowując klucze i indeksy.

Funkcje te są czytelniejsze niż ręczne opakowywanie potoków w [] i stanowią idiomatyczny styl jq w przypadku przekształceń, których wynikiem powinny pozostać tablice.

# map: extract a field from each element
echo '[{"name":"Alice","score":95},{"name":"Bob","score":80}]' \
  | jq 'map(.name)'
# Output: ["Alice", "Bob"]

# map with select: filter + transform in one step
echo '[{"name":"Alice","score":95},{"name":"Bob","score":60}]' \
  | jq 'map(select(.score >= 70) | .name)'
# Output: ["Alice"]

# map_values: multiply every value in an object by 2
echo '{"a":1,"b":2,"c":3}' | jq 'map_values(. * 2)'
# Output: {"a":2,"b":4,"c":6}

Obsługa pól opcjonalnych i wartości domyślnych za pomocą //

Dane JSON ze źródeł zewnętrznych często są niespójne — pól może brakować albo mogą mieć wartość null. jq udostępnia operator alternatywy // (podwójny ukośnik), który pozwala podać wartość domyślną.

  • .nickname // "anonymous" — używa .nickname, jeśli nie ma ona wartości null ani false; w przeciwnym razie używa "anonymous"
  • .count // 0 — wartość domyślna typu liczbowego
  • Można połączyć z select: select((.status // "inactive") == "active")

Jest to znacznie krótsze niż odpowiednik powłoki ${VAR:-default} i dobrze sprawdza się wewnątrz dłuższych potoków.

# Provide defaults for missing/null fields
echo '[{"name":"Alice","role":"admin"},{"name":"Bob"}]' \
  | jq '[.[] | {name, role: (.role // "user")}]'
# Output:
# [
#   {"name": "Alice", "role": "admin"},
#   {"name": "Bob",   "role": "user"}
# ]

# Numeric default
echo '{"items":[1,2,3]}' | jq '.total // 0'
# Output: 0

Praktyczny skrypt: analizator dzienników JSON

Rejestrowanie strukturalnych danych w formacie JSON jest standardem we współczesnych systemach. Oto realistyczny skrypt, który odczytuje plik dziennika zawierający po jednym obiekcie JSON w każdym wierszu, filtruje wpisy dotyczące błędów i formatuje czytelne dla człowieka podsumowanie.

Wykorzystane najważniejsze schematy:

  • -c (zwarty format danych wyjściowych) — jeden obiekt JSON w każdym wierszu, co jest przydatne podczas przekazywania danych do pętli powłoki
  • --arg name value — wstrzykuje zmienną powłoki jako argument tekstowy jq
  • select do filtrowania według poziomu dziennika
  • -r do generowania surowych danych tekstowych odpowiednich dla echo
#!/usr/bin/env bash
# Parse newline-delimited JSON logs and report ERRORs
# Each log line: {"level":"ERROR","msg":"...","ts":"2024-01-15T10:23:00Z","svc":"auth"}

LOG_FILE="/var/log/app/app.log"
LEVEL="ERROR"

echo "=== $LEVEL entries in $LOG_FILE ==="

jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | "[\(.ts)] [\(.svc)] \(.msg)"' \
  "$LOG_FILE"

# Count errors per service
echo ""
echo "=== Error count by service ==="
jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | .svc' "$LOG_FILE" \
  | sort | uniq -c | sort -rn

Sprawdzenie wiedzy: działanie select() w jq

Sprawdź swoją wiedzę na temat działania select() wewnątrz potoku jq.

Rozważ następujące polecenie:

echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":22}]' | jq '[.[] | select(.age >= 18) | .name]'

Jaki będzie wynik?

Podsumowanie lekcji: potoki jq do filtrowania JSON

Omówiono podstawowe narzędzia jq do nawigowania po danych JSON i filtrowania ich z poziomu wiersza poleceń:

  • Notacja kropkowa (.field, .a.b.c) wybiera pola z obiektów
  • Dostęp do tablic (.[0], .[]) umożliwia odwoływanie się do elementów tablic i iterowanie po nich
  • Operator potoku (|) łączy filtry; każdy etap przetwarza wszystkie wartości z poprzedniego etapu
  • select(cond) filtruje wartości, przekazując tylko te, dla których warunek ma wartość logiczną true
  • Tworzenie obiektów i tablic ({}, [], map()) przekształca dane w nowe struktury
  • Operator alternatywy (//) dostarcza wartości domyślne dla brakujących pól lub pól o wartości null
  • Flaga -r usuwa cudzysłowy przy przypisywaniu do zmiennej powłoki; --arg bezpiecznie wstrzykuje zmienne powłoki
  • Rekurencyjne przeszukiwanie (.. | .field?) przeszukuje głęboko zagnieżdżone drzewa, gdy ścieżka jest nieznana

Za pomocą tych elementów mogą Państwo przekształcić dowolną odpowiedź API w formacie JSON, plik dziennika lub konfigurację w dokładnie takie dane, jakich potrzebują skrypty — bez opuszczania terminala.

Często zadawane pytania

Czy lekcja „Filtrowanie i wybieranie JSON za pomocą potoków jq” jest bezpłatna?

Tak — pełny tekst „Filtrowanie i wybieranie JSON za pomocą potoków jq” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu DevOps Bootcamp, przejdź na CoddyKit PRO. Kurs DevOps Bootcamp zawiera 4 lekcji w sumie.

Co nauczysz się w „Filtrowanie i wybieranie JSON za pomocą potoków jq”?

Nawiguj po zagnieżdżonych obiektach i tablicach za pomocą selektorów jq, potoków oraz filtra select. Ćwiczysz DevOps Bootcamp z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć DevOps Bootcamp?

Nie wymagamy żadnego doświadczenia. DevOps Bootcamp w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Filtrowanie i wybieranie JSON za pomocą potoków jq”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji DevOps Bootcamp?

Tak. Każda lekcja DevOps Bootcamp zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Filtrowanie i wybieranie JSON za pomocą potoków jq
  2. Przekształcanie i tworzenie obiektów JSON za pomocą jq
  3. Korzystanie z REST API za pomocą curl i jq
  4. Edycja plików konfiguracyjnych YAML za pomocą yq
← Powrót do DevOps Bootcamp