Al

Alapok ebben a kurzusban: jq

1 feladat

A(z) Alapok fogalomról

A jq úgy működik, hogy a beérkező JSON-adatot egyetlen kifejezésen (amely szűrők folyamaként írható le) vezeti át, hogy elérje a kívánt átalakított adatot.

Gyors bevezetés a jq parancssori kapcsolóiba

A jq nyelvet a jq program valósítja meg. Ez a program számos hasznos parancssori kapcsolót kínál, amelyekkel szabályozhatod, hogyan fogyasztódik a bemenet, és hogyan jelenik meg a kimenet.

A következő példákban ezekkel találkozol majd:

  • -n vagy --null-input

    A jq programnak általában egy olvasandó fájlt adunk meg, vagy adatot küldesz a bemenetére. A --null-input kapcsolóval bemenet nélkül is előállíthatsz JSON-adatot.

  • -c vagy --compact-output

    A jq alapértelmezésben szépen formázva írja ki a kimenetét. Rendkívül hasznos, hogy az ember szépen formázva lássa az adatokat. A gépeknek viszont erre nincs szükségük: a --compact-output kapcsoló eltávolítja a formázó üres helyeket, hogy a lehető legkisebb legyen az eredményül kapott JSON.

  • -f filename vagy --from-file filename

    A jq programot a filename fájlból olvassa be, ahelyett hogy a parancssorban adnád meg. A sed és az awk ugyanerre a célra szintén a -f kapcsolót használja. Ezzel a gyakorlófeladatok tesztszkriptjeiben találkozol majd.

Az összes kapcsoló részleteit a kézikönyvben találod.

Szűrők és csövek

A szűrőket kifejezéseknek is nevezik.

A szűrő egy bemenetet fogad, és egy kimenetet állít elő. Ahogy a unix shellben is dolgozol, a szűrőket egy | csővel fűzheted össze, hogy az egyik szűrő kimenetét a másik bemenetére kösd.

Az identitásszűrő: .

Ez a legegyszerűbb szűrő. Egyszerűen átadja a bemenetét a kimenetének. Például a jq alapértelmezésben szépen formáz, így ha a . szűrőnek adsz JSON-t, ingyen szép formázott kimenetet kapsz!

$ echo '[1, 2, 3]' | jq '.'
[
  1,
  2,
  3
]

Tömbök

Ez egy gyors bevezetés a tömbökkel való munkába. Ezt a témát később részletesebben is tárgyaljuk.

A tömb elemeit zárójelekkel éred el, és a számozás nullától indul.

$ echo '[10, 20, 30]' | jq '.[1]'
20

A szűrő úgy építhet tömböt, hogy egy kifejezést [ és ] közé zár

  • ismert elemek listájával:

    jq -n '[1, 2, 3]'
    
  • elemek folyamának összegyűjtéséhez: például a range egy függvény, amely számok folyamát adja ki

    $ jq -n 'range(10; 70; 15)'
    10
    25
    40
    55
    

    A [] használatával a kifejezés eredményeit egy tömbbe gyűjtöd

    $ jq -c -n '[range(10; 70; 15)]'
    [10,25,40,55]
    

A vessző egy operátor

A vessző nem csupán szintaxis, amely elválasztja a tömb elemeit. A vessző egy operátor, amely folyamokat fűz össze.

Például a [1, 2, 3] egy szűrő, amely a [] _tömbkonstruktort használja, hogy összegyűjtse a 1, 2 és 3 kifejezések összefűzésének eredményét.

Feltűntek a fenti range(10; 70; 15) pontosvesszői? Mivel a vesszőknek meghatározott szerepük van a jq nyelvben, a több argumentumot fogadó függvények pontosvesszővel választják el az argumentumokat.

Objektumok

Gyors bevezetés az objektumokba.

Ahogy sok programozási nyelvben, itt is pontokkal éred el az objektum tulajdonságait

$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"

Zárójeleket az objektumoknál is használhatsz, de ilyenkor a string literálokhoz idézőjelek kellenek. Ez az egyik módja annak, hogy szóközt tartalmazó kulcsokkal dolgozz.

$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"

Egy objektumot {} és key: value párokkal építhetsz fel. Az olyan kulcsok körül, amelyek „egyszerű” stringek, nem kell idézőjel.

jq -n '{question: (6 * 9), answer: 42}'

az alábbi kimenetet adja:

{
  "question": 54,
  "answer": 42
}

Ahhoz, hogy a kulcsot kifejezésként kezeld, zárójelbe kell tenned (a következő is ugyanazt eredményezi, mint fent).

echo '[["question", "answer"], [54, 42]]' \
| jq '{(.[0][0]): .[1][0], (.[0][1]): .[1][1]}'
Note

Gyakori, hogy egy nagy objektumból a kulcsok egy részhalmazát szeretnéd kinyerni. Például hogy kinyerd az id és name kulcsot ebből:

{
    "id": 101,
    "name": "alpha widget",
    "specifications": {...}
}

Írhatnánk ezt:

{id: .id, name: .name}

De mivel ez olyan gyakori, van rá rövidített szintaxis:

{id, name}

Csővezetékek

Például ha a file.json ezt tartalmazza:

{
  "key1": "value1",
  "key2": [5, 15, 25]
}

Számítsuk ki a key2 tömb hosszát:

$ jq '.key2 | length' file.json
3

A .key2 kifejezés kimenetét csövezzük a length bemenetére, amely nem meglepő módon a tömb elemeinek számát adja ki.

Caution

A jq egyik olyan tulajdonsága ez, amelyhez hozzá kell szokni: a függvények többsége (de nem mindegyike) szűrőként viselkedik, azaz az adatot a szűrő bemenetére adod, nem argumentumként.

A szűrők figyelmen kívül hagyhatják a bemenetüket

Ebben a példában a bemenő JSON-adatot figyelmen kívül hagyjuk, és nincs hatással a kimenetre:

$ echo '{"answer": 42}' | jq '6 * 9'
54

A szűrők adatfolyamokat adhatnak ki

Egy szűrő egynél több értéket is kiadhat. Például a .[] szűrő a tömb minden elemét külön értékként adja ki:

$ jq -n -c '[1, 2, 3]'
[1,2,3]

$ jq -n -c '[1, 2, 3] | .[]'
1
2
3

Ha egy ilyen szűrőt egy másikba csövezünk, a második szűrő minden egyes értékre lefut:

$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6

Ez olyan, mint egy implicit iteráció. Ha egyszer megérted ezt a technikát, rájössz, hogy a nagyon erős jq szűrők is lehetnek nagyon tömörek.

Zárójelek

A zárójelekkel részkifejezéseket foghatsz össze, hogy érvényesítsd a műveletek sorrendjét, ahogy más nyelvekben is. A jq-ban néha meglepőnek tűnhet, hogy szükség van rájuk.

Például tegyük fel, hogy egy kételemű tömböt akarunk létrehozni: a 9 négyzetgyökét és az e-t az 1 hatványon. A két különálló kifejezés a 9 | sqrt és az 1 | exp. Azt várnánk, hogy a kimenet a [3, 2.7...] tömb legyen.

$ jq -n '[ 9|sqrt, 1|exp ]'
[
  20.085536923187668,
  2.718281828459045
]

Miért nem azt kaptuk, amire számítottunk? A jq így értelmezi:

[ ((9|sqrt), 1) | exp ]

A jq két elemből álló folyamot épít (3 és 1), amelyeket egyenként ad át az exp-nek.

Gondoskodnunk kell róla, hogy az exp csak egy számot kapjon bemenetként. Más szóval el kell érnünk, hogy a cső kiértékelése a vessző előtt történjen.

$ jq -n '[ 9|sqrt, (1|exp) ]'
[
  3,
  2.718281828459045
]

Típusok

A kézikönyvből

A jq ugyanazt az adattípuskészletet támogatja, mint a JSON: számok, stringek, Boolean-ok, tömbök, objektumok (amelyek a JSON szóhasználatában csak stringkulcsokat tartalmazó hash-ek), és a „null”.

Ezekről a későbbi feladatokban tanulsz majd többet.

Whitespace

A whitespace nem számít a jq-ban. Szóközöket, tabulátorokat és sortöréseket tetszés szerint használhatsz a kód formázásához. Nem tudunk semmilyen létező jq stílusútról.

Módosíthatatlan értékek

A jq-ban az értékek módosíthatatlanok. Az értéket módosító szűrők új értéket adnak ki. Ez azt jelenti, hogy a jq-ban nincsenek globális változók: hozzá kell szoknod, hogy az állapotot egyik szűrőtől a másikig add tovább.

„Truthiness”

A false és a null érték hamisnak számít. Minden más érték (beleértve a nulla számot és az üres stringet, tömböt, objektumot) igaz.

Függvények és operátorok

Anélkül, hogy mélyen belemennénk (a függvények egy másik feladat témája lesznek), íme néhány hasznos beépített függvény:

  • length

    Ha egy tömböt adsz bemenetként, kiadja a tömb elemeinek számát.

    $ jq -n '[10, 20, 30, 40] | length'
    4
    
  • +

    Ez az operátor az operandusai típusától függően mást tesz: összeadja a számokat, összefűzi a stringeket, hozzáfűzi a tömböket, egyesíti az objektumokat.

    $ jq -c -n '
        3 + 4,
        "foo" + "bar",
        ["a", "b"] + ["c"],
        {"m": 10} + {"n": 20}
    '
    7
    "foobar"
    ["a","b","c"]
    {"m":10,"n":20}
    

    Az add egy függvény, amely egy tömböt vesz át, és egyetlen értéket ad vissza, amelyben az összes elemet összeadta a + szabályai szerint. A [1, 2, 3] | add kimenete 6.

  • map

    Ha egy tömböt adsz bemenetként, és egy szűrőt argumentumként, akkor egy olyan tömböt ad ki, amelyben a szűrő minden elemre alkalmazva van

    $ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
    [2,4,6,8]
    
  • select

    Adott valamilyen bemenet és egy argumentumként kapott szűrő esetén:

    • ha az argumentumra alkalmazott szűrő igaz értéket ad, a bemenetet változatlanul kiadja
    • egyébként semmit nem ad ki (nem a null értéket, hanem tényleg semmit)

    Például adott néhány szám, válaszd ki a 3-mal oszthatókat

    $ jq -n 'range(10) | select(. % 3 == 0)'
    0
    3
    6
    9
    

    Emlékezz, hogy a range számok folyamát adja ki. A select minden számra egyszer hívódik meg. Csak azok a számok lesznek kiadva, amelyek „átmennek” a kifejezésen.

    Gyakran kell egy tömb elemeit kiválasztanod. Erre többféle módszer is van.

    A ["Anne", "Bob", "Cathy", "Dave"] bemenettel válaszd ki a 4 hosszúságú neveket.

    • használd a map-et és a select-et együtt

      map(select(length == 4))
      
    • bontsd fel a tömböt elemekre, alkalmazd a select-et arra a folyamra, és gyűjtsd össze az eredményeket

      [ .[] | select(length == 4) ]
      

Megjegyzések

A megjegyzések # karakterrel kezdődnek, és a sor végéig tartanak.

Szerkesztés GitHubon A hivatkozás új ablakban vagy lapon nyílik meg

Tanuld meg a(z) Alapok fogalmat