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.
jq parancssori kapcsolóibaA 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.
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.
.
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
]
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ő 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.
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]}'
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}
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.
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.
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
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.
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
]
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.
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.
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.
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.
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:
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.
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]
Adott valamilyen bemenet és egy argumentumként kapott szűrő esetén:
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) ]
A megjegyzések # karakterrel kezdődnek, és a sor végéig tartanak.