Hur man analyserar JSON-filer på Linux-kommandoraden med jq

Utforska JSON-data med kommandot jq i Linux

JSON (JavaScript Object Notation) har etablerat sig som ett av de mest använda formaten för dataöverföring på webben. Du stöter sannolikt på det ofta. I denna artikel visar vi hur du effektivt kan hantera JSON-data direkt från Linux-kommandoraden med hjälp av det kraftfulla verktyget jq.

JSON och jq: En djupare titt

JSON är en struktur för att koda data i vanliga textfiler på ett självbeskrivande sätt. En viktig aspekt av JSON är att den inte tillåter kommentarer, vilket understryker behovet av att data är självförklarande. Varje datavärde är kopplat till en textsträng, antingen känd som ett ”namn” eller en ”nyckel”, som definierar datans natur. Tillsammans bildar de ”namn:värde”- eller ”nyckel:värde”-par, separerade med ett kolon (:).

Ett ”objekt” i JSON utgörs av en samling av sådana nyckel:värde-par. Dessa objekt omges av klammerparenteser ({ och }). JSON stöder även ”arrayer”, som är ordnade listor av värden, omslutna av hakparenteser ([ och ]).

Dessa enkla byggstenar kan kombineras till komplexa strukturer, där objekt kan kapslas inuti varandra och arrayer kan innehålla både objekt och andra arrayer. Även om dessa möjligheter tillåter komplexa datamodeller, är det viktigt att tänka om layouten för att inte göra den onödigt svårhanterlig. Men om du arbetar med JSON som skapats av någon annan, får du helt enkelt acceptera strukturen som den är.

De flesta programmeringsspråk har bibliotek som underlättar parsning av JSON, men Bash-skalet saknar tyvärr den inbyggda kapaciteten. Detta är där verktyget jq kommer in i bilden. Med jq kan du enkelt tolka JSON-data direkt i Bash-skalet, oavsett komplexiteten i JSON-strukturen.

Installationsguide för jq

jq är inte alltid förinstallerat, så här följer några instruktioner för att installera det på olika Linux-distributioner:

Distribution Kommando
Ubuntu
sudo apt-get install jq
Fedora
sudo dnf install jq
Manjaro
sudo pacman -Sy jq

Förbättra läsbarheten av JSON

JSON-strukturer bryr sig inte om utrymmen, vilket innebär att layouten är irrelevant för maskiner. Detta gör det möjligt att sända JSON som en enda lång sträng, utan onödiga blanksteg, vilket sparar bandbredd. Dock kan en sådan presentation vara svårläst för människor.

Låt oss ta ett JSON-objekt från NASA som ger information om positionen för den Internationella rymdstationen, med hjälp av API:et. Vi använder curl, ett verktyg för att hämta filer. Med flaggan `-s` (tyst) undertrycker vi vanliga meddelanden från curl:

curl -s http://api.open-notify.org/iss-now.json

Denna utdata är svår att läsa. Låt oss använda jq för att förbättra läsbarheten.

jq använder filter för att analysera JSON och den enklaste av dessa är en punkt (.) som representerar hela objektet. Som standard formaterar jq utdata snyggt.

Vi kombinerar allt och skriver följande:

curl -s http://api.open-notify.org/iss-now.json | jq .

Nu är det tydligt att objektet omges av klammerparenteser och innehåller två nyckel:värde-par: `message` och `timestamp`, samt ett objekt som heter `iss_position`, vilket innehåller `longitude` och `latitude`.

Låt oss spara detta i en fil genom att skriva:

curl -s http://api.open-notify.org/iss-now.json | jq . > iss.json
cat iss.json

Vi har nu en snyggt formaterad JSON-fil lokalt.

Åtkomst till datavärden

jq kan extrahera data från både inkommande JSON och lokala JSON-filer. Här fokuserar vi på filer för att minska röran i kommandoraden.

För att extrahera data från en JSON-fil anger du nyckelns namn efter en punkt. Till exempel för att hämta `message` skriver vi:

jq .message iss.json

Om en nyckel innehåller blanksteg eller skiljetecken, måste du använda citattecken. I praktiken bör nycklar bara innehålla bokstäver, siffror och understreck.

För att hämta tidsstämpeln, skriver vi:

jq .timestamp iss.json

För att komma åt värden i `iss_position`-objektet använder vi ”punktnotation”, t.ex.:

jq .iss_position.latitude iss.json

För att extrahera flera värden:

  • Ange nyckelnamnen separerade med kommatecken (,).
  • Omge dem med citattecken (””) eller apostrofer (”).

Exempel:

jq ".iss_position.latitude, .timestamp" iss.json

Arbeta med arrayer

Låt oss ta ett annat JSON-objekt från NASA, denna gång en lista över astronauter i rymden:

curl -s http://api.open-notify.org/astros.json

Låt oss spara utdata i en fil som heter `astro.json`:

curl -s http://api.open-notify.org/astros.json | jq . > astro.json

Kontrollera filen med:

less astro.json

Detta JSON-objekt innehåller en array som heter `people`, där varje objekt har `name` och `craft` som nyckel:värde-par.

Vi kan använda punktnotation för att komma åt värden, men nu inkluderas även hakparenteser ([]) för arrayens namn, som i detta exempel:

jq ".people[].name" astro.json

För att hämta ett specifikt objekt använder vi indexering (nollbaserat).

För att komma åt det sista elementet i arrayen kan man använda index `-1`, näst sista med `-2` osv.

Vi kan skriva:

jq ".people[1].name" astro.json
jq ".people[3].name" astro.json
jq ".people[-1].name" astro.json
jq ".people[-2].name" astro.json

Det går också att hämta en ”skiva” (ett delområde) av arrayen, till exempel:

jq ".people[2:4]" astro.json

Detta ger oss elementet med index 2 och 3 (ej 4).

Använda rör med filter

Precis som i Linux-kommandoraden kan du ”pipa” utdata från ett jq-filter till ett annat med den vertikala stapeln (`|`).

Ett exempel på detta är:

jq ".people[] | .name" astro.json

Skapa och ändra data med jq

jq kan användas för att skapa nya arrayer, som i detta exempel:

jq "[.iss_position.latitude, .iss_position.longitude, .timestamp]" iss.json

Numeriska värden kan manipuleras:

jq ".timestamp" iss.json
jq ".timestamp - 1570000000" iss.json

För att se innehållet i filen igen:

jq . iss.json

Med `del()` kan vi ta bort ett nyckel:värde-par i jq:s utdata:

jq "del(.message)" iss.json

Obs: Detta påverkar inte den ursprungliga filen.

Mer komplexa JSON-strukturer

Vi hämtar mer data, denna gång information om meteornedslag från hela världen. Den här filen har en mer komplex JSON-struktur.

Låt oss spara den i filen `strikes.json`:

curl -s https://data.nasa.gov/resource/y77d-th95.json | jq . > strikes.json

Visa innehållet i filen:

less strikes.json

Filen börjar med en hakparentes (`[`), alltså är det en array av objekt, där varje objekt har nyckel:värde-par och ett kapslat objekt som heter `geolocation`. Detta innehåller också nyckel:värde-par och en array som heter `coordinates`.

För att hämta namnen på meteornedslagen från objektet med index 995 till slutet av arrayen:

jq ".[995:] |  .[] |  .name" strikes.json

Här är vad varje filter gör:

  • `.[995:]` – bearbetar objekten från index 995 till slutet.
  • `[]` – itererar genom arrayen.
  • `.name` – extraherar `name` värdet.

För att extrahera de sista 10 objekten ändrar vi `995` till `-10`:

jq ".[-10:] | .[] | .name" strikes.json

För att välja ett enskilt objekt:

jq ".[650].name" strikes.json

Vi kan också välja en ”skiva” av en sträng, t.ex. de första fyra tecknen:

jq ".[234].name[0:4]" strikes.json

För att se ett specifikt objekt i sin helhet:

jq ".[234]" strikes.json

För att se bara värdena:

jq ".[