Özet
jq [seçenekler...] filtre [dosyalar...]
jq; JSON belgelerini seçerek, yineleyerek, indirgeyerek ve başka şekillerde
düzenleyerek çeşitli yollarla dönüştürebilir. Örneğin, jq ´map(.price) | add´ komutunu
çalıştırmak, girdi olarak bir JSON nesnesi dizisi alacak ve bunların "price" (fiyat)
alanlarının toplamını döndürecektir.
jq düz metin girdilerini de kabul edebilir, ancak varsayılan olarak jq, standart girdiden (stdin)
bir JSON varlıkları akışını (sayılar ve diğer sabit değerler dahil) okur. 1 ve 2 veya true ve false
gibi varlıkları birbirinden ayırmak için yalnızca boşluk karakteri gereklidir. Bir veya daha fazla
dosya belirtilebilir, bu durumda jq girdiyi bunlar yerine o dosyalardan okuyacaktır.
Seçenekler [JQ ÇAĞIRMA] bölümünde açıklanmıştır; bunlar çoğunlukla girdi ve çıktı
biçimlendirmesi ile ilgilidir. Filtre, jq dilinde yazılır ve girdi dosyasının veya
belgesinin nasıl dönüştürüleceğini belirtir.
Filtreler
Bir jq programı bir "filtre"dir: bir girdi alır ve bir çıktı üretir. Bir nesnenin belirli bir alanını ayıklamak veya bir sayıyı dizeye dönüştürmek gibi çeşitli standart görevler için çok sayıda yerleşik filtre vardır.
Filtreler çeşitli şekillerde birleştirilebilir - bir filtrenin çıktısını başka bir filtreye yönlendirebilir (pipe) veya bir filtrenin çıktısını bir dizi içinde toplayabilirsiniz.
Bazı filtreler birden fazla sonuç üretir; örneğin, girdi dizisinin tüm öğelerini üreten bir filtre vardır. Bu filtreyi ikinci bir filtreye yönlendirmek, dizinin her bir öğesi için ikinci filtreyi çalıştırır. Genellikle diğer dillerde döngüler ve yineleme ile yapılacak şeyler, jq'da filtreleri birbirine yapıştırarak gerçekleştirilir.
Her filtrenin bir girdisi ve bir çıktısı olduğunu unutmamak önemlidir. "hello" veya 42 gibi sabit değerler (literals) bile filtredir - bir girdi alırlar ancak çıktı olarak her zaman aynı sabit değeri üretirler. İki filtreyi birleştiren işlemler (toplama gibi) genellikle her iki filtreye de aynı girdiyi besler ve sonuçları birleştirir. Böylece, bir ortalama filtresini add / length olarak uygulayabilirsiniz - girdi dizisini hem add filtresine hem de length filtresine besler ve ardından bölme işlemini gerçekleştirirsiniz.
Ama bu konuyu çok erkenden açmış olduk. :) Daha basit bir şeyle başlayalım:
Jq Çağırma
jq filtreleri bir JSON veri akışı üzerinde çalışır. jq girdisi, sağlanan filtreden teker teker geçirilen boşlukla ayrılmış JSON değerleri dizisi olarak ayrıştırılır. Filtrenin çıktı(ları), yeni satırla ayrılmış JSON verileri dizisi olarak standart çıktıya yazılır.
En basit ve en yaygın filtre (veya jq programı) olan ., jq işlemcisinin girdilerini çıktı akışına kopyalayan özdeşlik (identity) işlecidir. jq işlemcisinin varsayılan davranışı girdi akışından JSON metinlerini okumak ve çıktıları güzelce yazdırmak (pretty-print) olduğundan, . programının ana kullanımı girdileri doğrulamak ve güzelce yazdırmaktır. jq programlama dili oldukça zengindir ve yalnızca doğrulama ve güzel yazdırmadan çok daha fazlasına izin verir.
Not: Kabuğun (shell) tırnak kurallarına dikkat etmek önemlidir. Genel bir kural olarak, jq programını her zaman tırnak içine almak (Unix kabuklarında tek tırnak karakterleriyle) en iyisidir, çünkü jq için özel anlamı olan çok fazla karakter aynı zamanda kabuk meta-karakteridir. Örneğin, jq "foo" çoğu Unix kabuğunda başarısız olacaktır çünkü bu jq foo ile aynı şey olacaktır ve foo tanımlanmadığı için genellikle başarısız olacaktır. Windows komut istemini (cmd.exe) kullanırken komut satırında verildiğinde (-f program-dosyası seçeneği yerine) jq programınızın etrafında çift tırnak kullanmak en iyisidir, ancak bu durumda jq programındaki çift tırnakların ters eğik çizgi ile kaçış karakterine (escape) dönüştürülmesi gerekir. PowerShell (powershell.exe) veya PowerShell Core (pwsh/pwsh.exe) kullanırken, jq programının etrafında tek tırnak karakterleri ve jq programının içinde ters eğik çizgi ile kaçış uygulanmış çift tırnaklar (") kullanın.
• Unix kabukları: jq ´.["foo"]´
• PowerShell: jq ´.["foo"]´
• Windows komut istemi: jq ".["foo"]"
Not: jq kullanıcı tanımlı işlevlere izin verir, ancak her jq programının en üst düzeyde bir ifadesi olmalıdır.
Bazı komut satırı seçeneklerini kullanarak jq'nun girdisini nasıl okuduğunu ve çıktısını nasıl yazdığını etkileyebilirsiniz:
--null-input / -n:
Hiçbir girdi okumaz. Bunun yerine, filtre girdi olarak null kullanılarak bir kez çalıştırılır. Bu, jq'yu basit bir hesap makinesi olarak kullanırken veya sıfırdan JSON verileri oluştururken kullanışlıdır.
--raw-input / -R:
Girdiyi JSON olarak ayrıştırmaz. Bunun yerine, her metin satırı filtreye bir dize olarak aktarılır. --slurp ile birleştirilirse, tüm girdi filtreye tek bir uzun dize olarak aktarılır.
--slurp / -s:
Filtreyi girdideki her bir JSON nesnesi için ayrı ayrı çalıştırmak yerine, tüm girdi akışını büyük bir diziye okur ve filtreyi yalnızca bir kez çalıştırır.
--compact-output / -c:
Varsayılan olarak jq, JSON çıktısını güzelce yazdırır (pretty-print). Bu seçeneğin kullanılması, her JSON nesnesini tek bir satıra koyarak daha kompakt bir çıktı elde edilmesini sağlar.
--raw-output / -r:
Bu seçenekle, filtrenin sonucu bir dize ise, tırnak işaretleri içeren bir JSON dizesi olarak biçimlendirilmek yerine doğrudan standart çıktıya yazılır. Bu, jq filtrelerinin JSON tabanlı olmayan sistemlerle iletişim kurmasını sağlamak için yararlı olabilir.
--raw-output0:
-r gibidir ancak jq her çıktıdan sonra yeni satır yerine NUL karakteri yazdırır. Bu, çıktı olarak verilen değerlerin yeni satırlar içerebileceği durumlarda yararlı olabilir. Çıktı değeri NUL içerdiğinde, jq sıfır olmayan bir kodla çıkar.
--join-output / -j:
-r gibidir ancak jq her çıktıdan sonra yeni satır yazdırmaz.
--ascii-output / -a:
jq genellikle ASCII olmayan Unicode kod noktalarını, girdi bunları kaçış dizileri olarak (örneğin "\u03bc" gibi) belirtmiş olsa bile UTF-8 olarak çıkarır. Bu seçeneği kullanarak, jq'yu her ASCII dışı karakterin eşdeğer kaçış dizisiyle değiştirildiği saf ASCII çıktısı üretmeye zorlayabilirsiniz.
--sort-keys / -S:
Her nesnenin alanlarını, anahtarları (keys) sıralı olarak çıktı olarak verir.
--color-output / -C ve --monochrome-output / -M:
Varsayılan olarak jq, bir terminale yazıyorsa renkli JSON çıktısı verir. -C kullanarak bir boru hattına (pipe) veya dosyaya yazarken bile renk üretmeye zorlayabilir ve -M ile rengi devre dışı bırakabilirsiniz. NO_COLOR çevre değişkeni boş olmadığında, jq varsayılan olarak renkli çıktıyı devre dışı bırakır, ancak -C ile etkinleştirebilirsiniz.
Renkler JQ_COLORS çevre değişkeni ile yapılandırılabilir (aşağıya bakın).
--tab:
İki boşluk yerine her girinti düzeyi için bir sekme (tab) karakteri kullanır.
--indent n:
Girinti için belirtilen sayıda boşluk (en fazla 7) kullanır.
--unbuffered:
Her JSON nesnesi yazdırıldıktan sonra çıktıyı boşaltır (yavaş bir veri kaynağını jq'ya yönlendiriyorsanız ve jq'nun çıktısını başka bir yere yönlendiriyorsanız kullanışlıdır).
--stream:
Girdiyi akışsal (streaming) biçimde ayrıştırır, yol (path) ve yaprak (leaf) değerlerinin dizilerini (skalerler ve boş diziler veya boş nesneler) çıktı olarak verir. Örneğin, "a" değeri [[],"a"] haline gelir ve [[],"a",["b"]] değeri [[0],[]], [[1],"a"] ve [[2,0],"b"] haline gelir.
Bu, çok büyük girdileri işlemek için kullanışlıdır. Büyük girdileri aşamalı olarak azaltmak için bunu filtreleme ve reduce ile foreach sözdizimleriyle birlikte kullanın.
--stream-errors:
--stream gibidir, ancak geçersiz JSON girdileri, ilk öğenin hata ve ikincinin bir yol (path) olduğu dizi değerleri üretir. Örneğin, ["a",n] girdisi ["Invalid literal at line 1, column 7",[1]] üretir.
--stream seçeneğini ima eder. --stream-errors olmadan --stream kullanıldığında geçersiz JSON girdileri hiçbir hata değeri üretmez.
--seq:
jq'nun girdi ve çıktısında JSON metinlerini ayırmak için application/json-seq MIME türü şemasını kullanır. Bu, çıktıdaki her değerden önce bir ASCII RS (kayıt ayırıcı) karakterinin yazdırıldığı ve her çıktıdan sonra bir ASCII LF (satır besleme) yazdırıldığı anlamına gelir. Ayrıştırılamayan girdi JSON metinleri yoksayılır (ancak uyarılır) ve bir sonraki RS karakterine kadar sonraki tüm girdiler atılır. Bu mod ayrıca --seq seçeneği olmadan jq'nun çıktısını da ayrıştırır.
-f dosya_adı / --from-file dosya_adı:
Filtreyi komut satırı yerine dosyadan okur (awk'ın -f seçeneği gibi). Yorum yapmak için ´#´ karakterini de kullanabilirsiniz.
-L dizin:
Modüller için arama listesinin başına dizini ekler. Bu seçenek kullanılırsa hiçbir yerleşik arama listesi kullanılmaz. Aşağıdaki modüller bölümüne bakın.
--arg ad değer:
Bu seçenek, jq programına önceden tanımlanmış bir değişken olarak bir değer aktarır. jq'yu --arg foo bar ile çalıştırırsanız, programda $foo kullanılabilir durumdadır ve "bar" değerine sahiptir. Değerin bir dize olarak ele alınacağını unutmayın, bu nedenle --arg foo 123 ifadesi $foo değişkenini "123" dizesine bağlayacaktır.
Adlandırılmış argümanlar, jq programına $ARGS.named olarak da sunulur.
--argjson ad JSON-metni:
Bu seçenek, jq programına önceden tanımlanmış bir değişken olarak JSON kodlu bir değer aktarır. jq'yu --argjson foo 123 ile çalıştırırsanız, programda $foo kullanılabilir durumdadır ve 123 değerine sahiptir.
--slurpfile değişken-adı dosya-adı:
Bu seçenek, belirtilen dosyadaki tüm JSON metinlerini okur ve ayrıştırılan JSON değerlerinin bir dizisini belirtilen genel değişkene bağlar. jq'yu --slurpfile foo bar ile çalıştırırsanız, programda $foo kullanılabilir durumdadır ve bar adlı dosyadaki metinlere karşılık gelen öğeleri içeren bir diziye sahiptir.
--rawfile değişken-adı dosya-adı:
Bu seçenek, belirtilen dosyayı okur ve içeriğini belirtilen genel değişkene bağlar. jq'yu --rawfile foo bar ile çalıştırırsanız, programda $foo kullanılabilir durumdadır ve içeriği bar adlı dosyadaki metinler olan bir dizeye sahiptir.
--args:
Kalan argümanlar konumsal dize argümanlarıdır. Bunlar jq programına $ARGS.positional[] olarak sunulur.
--jsonargs:
Kalan argümanlar konumsal JSON metin argümanlarıdır. Bunlar jq programına $ARGS.positional[] olarak sunulur.
--exit-status / -e:
Son çıktı değeri ne false ne de null ise jq'nun çıkış durumunu (exit status) 0, son çıktı değeri false veya null ise 1 veya hiçbir zaman geçerli bir sonuç üretilmediyse 4 olarak ayarlar. Normalde jq, herhangi bir kullanım sorunu veya sistem hatası varsa 2, bir jq programı derleme hatası varsa 3 veya jq programı çalıştıysa 0 ile çıkar.
Çıkış durumunu ayarlamanın başka bir yolu da yerleşik halt_error işlevidir.
--binary / -b:
WSL, MSYS2 veya Cygwin kullanan Windows kullanıcıları yerel bir jq.exe kullanırken bu seçeneği kullanmalıdır; aksi takdirde jq, yeni satırları (LF) satırbaşı ve yeni satıra (CRLF) dönüştürecektir.
--version / -V:
jq sürümünü yazdırır ve sıfır koduyla çıkar.
--build-configuration:
jq'nun derleme yapılandırmasını (build configuration) yazdırır ve sıfır koduyla çıkar. Bu çıktının desteklenen bir biçimi veya yapısı yoktur ve gelecekteki sürümlerde haber verilmeksizin değişebilir.
--help / -h:
jq yardım metnini yazdırır ve sıfır koduyla çıkar.
--:
Argüman işlemeyi sonlandırır. Kalan argümanlar seçenek olarak yorumlanmaz.
--run-tests [dosya_adı]:
Belirtilen dosyadaki veya standart girdideki testleri çalıştırır. Bu, verilen son seçenek olmalıdır ve önceki tüm seçenekleri dikkate almaz. Girdi; yorum satırlarından, boş satırlardan ve program satırlarından oluşur, bunları bir girdi satırı, beklendiği kadar çıktı satırı (her çıktı için bir satır) ve sonlandırıcı boş bir satır takip eder. Derleme hatası testleri, yalnızca %%FAIL içeren bir satırla başlar, ardından derlenecek programı içeren bir satır ve ardından gerçek hatayla karşılaştırılacak hata mesajını içeren bir satır gelir.
Bu seçeneğin geriye dönük uyumsuz bir şekilde değişebileceği konusunda uyarılmalıdır.
Temel Filtreler
Özdeşlik: . En basit filtre . 'dır. Bu filtre girdisini alır ve çıktı olarak aynı değeri üretir. Yani bu, özdeşlik (identity) işlecidir.
jq varsayılan olarak tüm çıktıları güzelce yazdırdığından, yalnızca . 'dan oluşan önemsiz bir program, örneğin curl'den gelen JSON çıktısını biçimlendirmek için kullanılabilir.
Özdeşlik filtresi girdisinin değerini asla değiştirmese de, jq işlemesi bazen değiştirmiş gibi görünmesine neden olabilir. Örneğin, jq'nun mevcut uygulamasını kullanarak şu ifadenin:
1E1234567890 | .
en az bir platformda 1.7976931348623157e+308 ürettiğini görürüz. Bunun nedeni, sayıyı ayrıştırma sürecinde, jq'nun bu özel sürümünün bunu bir IEEE754 çift duyarlıklı (double-precision) gösterimine dönüştürmesi ve hassasiyet kaybetmesidir.
jq'nun sayıları işleme biçimi zaman içinde değişmiştir ve ilgili JSON standartları tarafından belirlenen parametreler dahilinde daha fazla değişiklik yapılması muhtemeldir. Bu nedenle, aşağıdaki açıklamalar jq'nun mevcut sürümünü tanımlamaya yönelik olduğu ve kural koyucu (prescriptive) olarak yorumlanmaması gerektiği bilinciyle sunulmaktadır:
(1) Halihazırda bir IEEE754 çift duyarlıklı gösterime dönüştürülmemiş bir sayı üzerindeki herhangi bir aritmetik işlem, IEEE754 gösterimine dönüştürmeyi tetikleyecektir.
(2) jq, sayı sabitlerinin orijinal ondalık hassasiyetini korumaya çalışacaktır, ancak 1E1234567890 gibi ifadelerde üstel değer çok büyükse hassasiyet kaybolacaktır.
(3) jq programlarında, baştaki eksi işareti sayının IEEE754 gösterimine dönüştürülmesini tetikleyecektir.
(4) Karşılaştırmalar, aşağıdaki örneklerden birinde gösterildiği gibi, mevcutsa sayıların kırpılmamış büyük ondalık (big decimal) gösterimi kullanılarak gerçekleştirilir.
jq ´.´ "Hello, world!" => "Hello, world!"
jq ´.´ 0.12345678901234567890123456789 => 0.12345678901234567890123456789
jq ´[., tojson]´ 12345678909876543212345 => [12345678909876543212345,"12345678909876543212345"]
jq ´. < 0.12345678901234567890123456788´ 0.12345678901234567890123456789 => false
jq ´map([., . == 1]) | tojson´ [1, 1.000, 1.0, 100e-2] => "[[1,true],[1.000,true],[1.0,true],[1.00,true]]"
jq ´. as $big | [$big, $big + 1] | map(. > 10000000000000000000000000000000)´ 10000000000000000000000000000001 => [true, false]
Nesne Belirteç-İndeksi: .foo, .foo.bar En basit yararlı filtre .foo biçimindedir. Girdi olarak bir JSON nesnesi (diğer adıyla sözlük veya hash) verildiğinde, .foo, anahtar mevcutsa "foo" anahtarındaki değeri, aksi takdirde null üretir.
.foo.bar biçimindeki bir filtre, .foo | .bar ifadesine eşdeğerdir.
.foo sözdizimi yalnızca basit, tanımlayıcı benzeri (identifier-like) anahtarlar için çalışır; yani tamamen alfasayısal karakterlerden ve alt çizgiden oluşan ve bir rakamla başlamayan anahtarlar.
Anahtar özel karakterler içeriyorsa veya bir rakamla başlıyorsa, bunu şu şekilde çift tırnak içine almanız gerekir: ."foo$" veya .["foo$"].
Örneğin .["foo::bar"] ve .["foo.bar"] çalışırken .foo::bar çalışmaz.
jq ´.foo´ {"foo": 42, "bar": "less interesting data"} => 42
jq ´.foo´ {"notfoo": true, "alsonotfoo": false} => null
jq ´.["foo"]´ {"foo": 42} => 42
İsteğe Bağlı Nesne Belirteç-İndeksi: .foo? Tıpkı .foo gibidir, ancak . bir nesne olmadığında hata çıktısı vermez.
jq ´.foo?´ {"foo": 42, "bar": "less interesting data"} => 42
jq ´.foo?´ {"notfoo": true, "alsonotfoo": false} => null
jq ´.["foo"]?´ {"foo": 42} => 42
jq ´[.foo?]´ [1,2] => []
Nesne İndeksi: .[
Dizi İndeksi: .[<sayı>] İndeks değeri bir tamsayı olduğunda, .[<sayı>] dizileri indeksleyebilir. Diziler sıfır tabanlıdır, bu nedenle .[2] üçüncü öğeyi döndürür.
Negatif indekslere izin verilir; -1 son öğeyi, -2 sondan bir önceki öğeyi vb. belirtir.
jq ´.[0]´ [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => {"name":"JSON", "good":true}
jq ´.[2]´ [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => null
jq ´.[-2]´ [1,2,3] => 2
Dizi/Dize Dilimi: .[<sayı>:<sayı>] .[<sayı>:<sayı>] sözdizimi, bir dizinin alt dizisini veya bir dizenin alt dizesini döndürmek için kullanılabilir. .[10:15] tarafından döndürülen dizi 5 uzunluğunda olacak ve indeks 10'dan (dahil) indeks 15'e (hariç) kadar olan öğeleri içerecektir. İndekslerden herhangi biri negatif olabilir (bu durumda dizinin sonundan geriye doğru sayılır) veya atlanabilir (bu durumda dizinin başlangıcını veya sonunu belirtir). İndeksler sıfır tabanlıdır.
jq ´.[2:4]´ ["a","b","c","d","e"] => ["c", "d"]
jq ´.[2:4]´ "abcdefghi" => "cd"
jq ´.[:3]´ ["a","b","c","d","e"] => ["a", "b", "c"]
jq ´.[-2:]´ ["a","b","c","d","e"] => ["d", "e"]
Dizi/Nesne Değer Yineleyicisi: .[] .[indeks] sözdizimini kullanır ancak indeksi tamamen atlarsanız, bir dizinin tüm öğelerini döndürecektir. [1,2,3] girdisiyle .[] çalıştırmak, sayıları tek bir dizi yerine üç ayrı sonuç olarak üretecektir. .foo[] biçimindeki bir filtre, .foo | .[] ifadesine eşdeğerdir.
Bunu bir nesne üzerinde de kullanabilirsiniz ve nesnenin tüm değerlerini döndürecektir.
Yineleyici (iterator) işlecinin bir değer üreteci (generator) olduğunu unutmayın.
jq ´.[]´ [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => {"name":"JSON", "good":true}, {"name":"XML", "good":false}
jq ´.[]´ [] =>
jq ´.foo[]´ {"foo":[1,2,3]} => 1, 2, 3
jq ´.[]´ {"a": 1, "b": 1} => 1, 1
.[]? .[] gibidir, ancak . bir dizi veya nesne olmadığında hata çıktısı verilmez. .foo[]? biçimindeki bir filtre, .foo | .[]? ifadesine eşdeğerdir.
Virgül: , İki filtre bir virgülle ayrılırsa, her ikisine de aynı girdi beslenir ve iki filtrenin çıktı değer akışları sırayla birleştirilir: önce sol ifadenin ürettiği tüm çıktılar ve ardından sağ ifadenin ürettiği tüm çıktılar. Örneğin, .foo, .bar filtresi hem "foo" alanlarını hem birer ayrı çıktı olarak hem de "bar" alanlarını üretir.
, işleci, üreteçler (generators) oluşturmanın bir yoludur.
jq ´.foo, .bar´ {"foo": 42, "bar": "something else", "baz": true} => 42, "something else"
jq ´.user, .projects[]´ {"user":"stedolan", "projects": ["jq", "wikiflow"]} => "stedolan", "jq", "wikiflow"
jq ´.[4,2]´ ["a","b","c","d","e"] => "e", "c"
Yönlendirme (Pipe): | | işleci, soldakinin çıktı(larını) sağdakinin girdisine besleyerek iki filtreyi birleştirir. Eğer alışkınsanız, Unix kabuğunun boru hattına (pipe) benzer.
Soldaki birden fazla sonuç üretiyorsa, sağdaki bu sonuçların her biri için çalıştırılacaktır. Dolayısıyla, .[] | .foo ifadesi, girdi dizisinin her bir öğesinin "foo" alanını alır. Bu, şaşırtıcı olabilen bir kartezyen çarpımdır.
.a.b.c ifadesinin .a | .b | .c ile aynı olduğunu unutmayın.
Ayrıca . öğesinin, bir "boru hattı"ndaki belirli bir aşamadaki, özellikle de . ifadesinin göründüğü yerdeki girdi değeri olduğunu unutmayın. Dolayısıyla .a | . | .b ifadesi .a.b ile aynıdır, çünkü ortadaki . ifadesi .a'nın ürettiği değer ne olursa olsun onu belirtir.
jq ´.[] | .name´ [{"name":"JSON", "good":true}, {"name":"XML", "good":false}] => "JSON", "XML"
Parantez Parantezler, tıpkı tipik herhangi bir programlama dilinde olduğu gibi bir gruplama işleci olarak çalışır.
jq ´(. + 2) * 5´ 1 => 15
Tipler Ve Değerler
jq, JSON ile aynı veri tiplerini destekler - sayılar, dizeler, boolean'lar, diziler, nesneler (JSON dilinde yalnızca dize anahtarları olan hash'ler) ve "null".
Boolean'lar, null, dizeler ve sayılar JSON'daki ile aynı şekilde yazılır. jq'daki diğer her şey gibi, bu basit değerler de bir girdi alır ve bir çıktı üretir - 42, bir girdi alan, bunu yoksayan ve yerine 42 döndüren geçerli bir jq ifadesidir.
jq'daki sayılar dahili olarak IEEE754 çift duyarlıklı yaklaşıklığıyla temsil edilir. Sayılarla yapılan herhangi bir aritmetik işlem, bunlar sabit değerler veya önceki filtrelerin sonuçları olsun, çift duyarlıklı bir kayan noktalı sonuç üretecektir.
Ancak, jq bir sabit değeri ayrıştırırken orijinal sabit dizesini saklayacaktır. Bu değer üzerinde hiçbir değişiklik uygulanmazsa, çift duyarlıklı sayıya dönüştürme bir kayba neden olsa bile çıktıya orijinal biçiminde ulaşacaktır.
Dizi oluşturma: [] JSON'da olduğu gibi, [] diziler oluşturmak için kullanılır, örneğin [1,2,3] gibi. Dizinin öğeleri, bir boru hattı dahil olmak üzere herhangi bir jq ifadesi olabilir. Tüm ifadeler tarafından üretilen tüm sonuçlar tek bir büyük dizi içinde toplanır. Bunu, bilinen miktardaki değerlerden bir dizi oluşturmak için (örneğin [.foo, .bar, .baz] gibi) veya bir filtrenin tüm sonuçlarını bir dizi içinde "toplamak" için (örneğin [.items[].name] gibi) kullanabilirsiniz.
"," işlecini anladıktan sonra, jq'nun dizi sözdizimine farklı bir açıdan bakabilirsiniz: [1,2,3] ifadesi, virgülle ayrılmış diziler için yerleşik bir sözdizimi kullanmamakta, bunun yerine 1,2,3 ifadesine (üç farklı sonuç üreten) [] işlecini (sonuçları topla) uygulamaktadır.
Dört sonuç üreten bir X filtreniz varsa, [X] ifadesi tek bir sonuç, yani dört öğeli bir dizi üretecektir.
jq ´[.user, .projects[]]´ {"user":"stedolan", "projects": ["jq", "wikiflow"]} => ["stedolan", "jq", "wikiflow"]
jq ´[ .[] | . * 2]´ [1, 2, 3] => [2, 4, 6]
Nesne Oluşturma: {} JSON gibi, {} nesneler (sözlükler veya hash'ler) oluşturmak içindir, örneğin: {"a": 42, "b": 17}.
Anahtarlar "tanımlayıcı benzeri" ise, tırnak işaretleri dışarıda bırakılabilir, örneğin {a:42, b:17} gibi. Anahtar ifadeleri olarak değişken referansları, değişkenin değerini anahtar olarak kullanır. Sabit değerler, tanımlayıcılar veya değişken referansları dışındaki anahtar ifadelerinin parantez içine alınması gerekir, örneğin {("a"+"b"):59}.
Değer herhangi bir ifade olabilir (örneğin, iki nokta üst üste içeriyorsa parantez içine almanız gerekebilir), bu da {} ifadesinin girdisine uygulanır (unutmayın, tüm filtrelerin bir girdisi ve bir çıktısı vardır).
{foo: .bar}
girdi olarak {"bar":42, "baz":43} JSON nesnesi verilirse {"foo": 42} JSON nesnesini üretecektir. Bunu bir nesnenin belirli alanlarını seçmek için kullanabilirsiniz: girdi "user", "title", "id" ve "content" alanlarına sahip bir nesneyse ve siz yalnızca "user" ve "title" alanlarını istiyorsanız, şunu yazabilirsiniz:
{user: .user, title: .title}
Bu çok yaygın olduğu için bunun bir kısayol sözdizimi vardır: {user, title}.
İfadelerden biri birden fazla sonuç üretirse, birden fazla sözlük üretilecektir. Eğer girdi:
{"user":"stedolan","titles":["JQ Primer", "More JQ"]}
ise, o zaman şu ifade:
{user, title: .titles[]}
iki çıktı üretecektir:
{"user":"stedolan", "title": "JQ Primer"} {"user":"stedolan", "title": "More JQ"}
Anahtarın etrafına parantez koymak, bunun bir ifade olarak değerlendirileceği anlamına gelir. Yukarıdaki girdiyle aynı şekilde,
{(.user): .titles}
şunu üretir:
{"stedolan": ["JQ Primer", "More JQ"]}
Anahtar olarak değişken referansları, değişkenin değerini anahtar olarak kullanır. Bir değer olmadan, değişkenin adı anahtar ve değeri de değer haline gelir,
"f o o" as $foo | "b a r" as $bar | {$foo, $bar:$foo}
şunu üretir:
{"foo":"f o o","b a r":"f o o"}
jq ´{user, title: .titles[]}´ {"user":"stedolan","titles":["JQ Primer", "More JQ"]} => {"user":"stedolan", "title": "JQ Primer"}, {"user":"stedolan", "title": "More JQ"}
jq ´{(.user): .titles}´ {"user":"stedolan","titles":["JQ Primer", "More JQ"]} => {"stedolan": ["JQ Primer", "More JQ"]}
Özyinelemeli İniş (Recursive Descent): .. Özyinelemeli olarak .'a iner ve her değeri üretir. Bu, sıfır argümanlı yerleşik recurse işleviyle aynıdır (aşağıya bakın). Bunun XPath // işlecine benzemesi amaçlanmıştır. ..a ifadesinin çalışmadığını unutmayın; bunun yerine .. | .a kullanın. Aşağıdaki örnekte, .. "altında" bulunan herhangi bir nesnedeki "a" nesne anahtarlarının tüm değerlerini bulmak için .. | .a? kullanıyoruz.
Bu, özellikle path(EXP) (ayrıca aşağıya bakın) ve ? işleciyle birlikte kullanışlıdır.
jq ´.. | .a?´ [[{"a":1}]] => 1
YERLEŞİK İŞLEÇLER VE İŞLEVLER Bazı jq işleçleri (örneğin, +) argümanlarının türüne (diziler, sayılar vb.) bağlı olarak farklı şeyler yapar. Ancak jq asla örtük tür dönüşümleri yapmaz. Bir nesneye dize eklemeye çalışırsanız, bir hata mesajı alırsınız ve sonuç elde edemezsiniz.
Lütfen tüm sayıların IEEE754 çift duyarlıklı kayan noktalı sayı gösterimine dönüştürüldüğünü unutmayın. Aritmetik ve mantıksal işleçler bu dönüştürülmüş çift duyarlıklı sayılarla çalışır. Bu tür tüm işlemlerin sonuçları da çift duyarlılıkla sınırlıdır.
Sayıların bu davranışının tek istisnası, orijinal sayı sabitinin anlık görüntüsüdür. Başlangıçta sabit değer olarak sağlanan bir sayı, programın sonuna kadar hiç değiştirilmezse, çıktıya orijinal sabit biçiminde yazdırılır. Bu, orijinal sabit değerin IEEE754 çift duyarlıklı kayan noktalı sayıya dönüştürüldüğünde kırpılacağı durumları da içerir.
Toplama: +
- işleci iki filtre alır, her ikisini de aynı girdiye uygular ve sonuçları birbirine ekler. "Eklemenin" ne anlama geldiği ilgili türlere bağlıdır:
• Sayılar normal aritmetikle toplanır.
• Diziler daha büyük bir dizi halinde birleştirilerek (concatenate) eklenir.
• Dizeler daha büyük bir dize halinde birleştirilerek eklenir.
• Nesneler birleştirilerek (merge), yani her iki nesnedeki tüm anahtar-değer çiftleri tek bir birleşik nesneye eklenerek toplanır. Her iki nesne de aynı anahtar için bir değer içeriyorsa, +'nın sağındaki nesne kazanır. (Özyinelemeli birleştirme için * işlecini kullanın.)
null herhangi bir değere eklenebilir ve diğer değeri değiştirmeden döndürür.
jq ´.a + 1´ {"a": 7} => 8
jq ´.a + .b´ {"a": [1,2], "b": [3,4]} => [1,2,3,4]
jq ´.a + null´ {"a": 1} => 1
jq ´.a + 1´ {} => 1
jq ´{a: 1} + {b: 2} + {c: 3} + {a: 42}´ null => {"a": 42, "b": 2, "c": 3}
Çıkarma: - Sayılar üzerindeki normal aritmetik çıkarmanın yanı sıra, - işleci diziler üzerinde, ikinci dizinin öğelerinin tüm örneklerini ilk diziden kaldırmak için kullanılabilir.
jq ´4 - .a´ {"a":3} => 1
jq ´. - ["xml", "yaml"]´ ["xml", "yaml", "json"] => ["json"]
Çarpma, bölme, modül: *, /, % Bu eklemeli (infix) işleçler, iki sayı verildiğinde beklendiği gibi davranır. Sıfıra bölme bir hata oluşturur. x % y, x modül y değerini hesaplar.
Bir dizeyi bir sayıyla çarpmak, o dizeyi o kadar kez birleştirerek üretir. "x" * 0, "" üretir.
Bir dizeyi diğerine bölmek, ilkini ikinciyi ayırıcı olarak kullanarak böler.
İki nesneyi çarpmak onları özyinelemeli olarak birleştirir: bu toplama gibi çalışır, ancak her iki nesne de aynı anahtar için bir değer içeriyorsa ve değerler nesne ise, ikisi aynı stratejiyle birleştirilir.
jq ´10 / . * 3´ 5 => 6
jq ´. / ", "´ "a, b,c,d, e" => ["a","b,c,d","e"]
jq ´{"k": {"a": 1, "b": 2}} * {"k": {"a": 0,"c": 3}}´ null => {"k": {"a": 0, "b": 2, "c": 3}}
jq ´.[] | (1 / .)?´ [1,0,-1] => 1, -1
abs Yerleşik abs işlevi saf bir şekilde şu şekilde tanımlanır: if . < 0 then - . else . end.
Sayısal girdi için bu mutlak değerdir. Sayısal girdi için bu tanımın doğurduğu sonuçlar hakkında bilgi edinmek için özdeşlik filtresi bölümüne bakın.
Bir sayının mutlak değerini kayan noktalı sayı olarak hesaplamak için fabs kullanmak isteyebilirsiniz.
jq ´map(abs)´ [-10, -1.1, -1e-1] => [10,1.1,1e-1]
length Yerleşik length işlevi, çeşitli farklı değer türlerinin uzunluğunu alır:
• Bir dizenin uzunluğu, içerdiği Unicode kod noktalarının sayısıdır (saf ASCII ise bayt cinsinden JSON kodlu uzunluğu ile aynı olacaktır).
• Bir sayının uzunluğu onun mutlak değeridir.
• Bir dizinin uzunluğu öğe sayısıdır.
• Bir nesnenin uzunluğu anahtar-değer çiftlerinin sayısıdır.
• null uzunluğu sıfırdır.
• Bir boolean üzerinde length kullanılması hatadır.
jq ´.[] | length´ [[1,2], "string", {"a":2}, null, -5] => 2, 6, 1, 0, 5
utf8bytelength Yerleşik utf8bytelength işlevi, bir dizeyi UTF-8'de kodlamak için kullanılan bayt sayısını verir.
jq ´utf8bytelength´ "\u03bc" => 2
keys, keys_unsorted Yerleşik keys işlevi, bir nesne verildiğinde anahtarlarını bir dizi içinde döndürür.
Anahtarlar, Unicode kod noktası sırasına göre "alfabetik olarak" sıralanır. Bu, herhangi bir dilde özel bir anlam ifade eden bir sıralama değildir, ancak yerel ayarlar ne olursa olsun aynı anahtar kümesine sahip herhangi iki nesne için aynı olacağına güvenebilirsiniz.
keys'e bir dizi verildiğinde, o dizi için geçerli indeksleri döndürür: 0 ile length-1 arasındaki tamsayılar.
keys_unsorted işlevi tıpkı keys gibidir, ancak girdi bir nesne ise anahtarlar sıralanmaz, bunun yerine anahtarlar kabaca ekleme sırasına göre gelir.
jq ´keys´ {"abc": 1, "abcd": 2, "Foo": 3} => ["Foo", "abc", "abcd"]
jq ´keys´ [42,3,35] => [0,1,2]
has(key) Yerleşik has işlevi, girdi nesnesinin belirtilen anahtara sahip olup olmadığını veya girdi dizisinin belirtilen indekste bir öğeye sahip olup olmadığını döndürür.
has($key), has daha hızlı olmasına rağmen, $key'in keys tarafından döndürülen dizinin bir üyesi olup olmadığını kontrol etmekle aynı etkiye sahiptir.
jq ´map(has("foo"))´ [{"foo": 42}, {}] => [true, false]
jq ´map(has(2))´ [[0,1], ["a","b","c"]] => [false, true]
in Yerleşik in işlevi, girdi anahtarının verilen nesnede olup olmadığını veya girdi indeksinin verilen dizideki bir öğeye karşılık gelip gelmediğini döndürür. Esasen, has işlevinin ters çevrilmiş bir versiyonudur.
jq ´.[] | in({"foo": 42})´ ["foo", "bar"] => true, false
jq ´map(in([0,1]))´ [2, 0] => [false, true]
map(f), map_values(f) Herhangi bir f filtresi için map(f) ve map_values(f), girdi dizisindeki veya nesnesindeki değerlerin her birine f'yi uygular, yani .[] değerlerine uygular.
Hataların yokluğunda, map(f) her zaman bir dizi çıktısı verirken map_values(f), dizi verilirse dizi, nesne verilirse nesne çıktısı verir.
map_values(f) fonksiyonunun girdisi bir nesne (object) olduğunda, çıktı nesnesi, değerleri f fonksiyonuna aktarıldığında (piped) hiç değer üretmeyen anahtarlar hariç olmak üzere, girdi nesnesi ile aynı anahtarlara sahip olur.
map(f) ile map_values(f) arasındaki temel fark; ilkinin girdi dizisindeki (array) veya nesnesindeki her bir $x değeri için, ($x|f) ifadesinin ürettiği tüm değerlerden basitçe bir dizi oluşturması, map_values(f) fonksiyonunun ise yalnızca first($x|f) değerini kullanmasıdır.
Özellikle, nesne girdileri için map_value(f), girdinin her bir $k anahtarı için sırasıyla first(.[$k]|f) değerini inceleyerek çıktı nesnesini oluşturur. Eğer bu ifade hiçbir değer üretmezse, ilgili anahtar düşürülür; aksi takdirde çıktı nesnesi, $k anahtarında bu değere sahip olur.
Aşağıda, dizilere uygulandığında map ve map_values davranışlarını netleştirmek için bazı örnekler verilmiştir. Bu örneklerin tamamında girdinin [1] olduğu varsayılmaktadır:
map(.+1) #=> [2] map(., .) #=> [1,1] map(empty) #=> []
map_values(.+1) #=> [2] map_values(., .) #=> [1] map_values(empty) #=> []
map(f) ifadesi [.[] | f] ifadesine, map_values(f) ifadesi ise .[] |= f ifadesine eşdeğerdir.
Aslında bunlar, ilgili fonksiyonların kendi uygulamalarıdır (implementations).
jq ´map(.+1)´ [1,2,3] => [2,3,4]
jq ´map_values(.+1)´ {"a": 1, "b": 2, "c": 3} => {"a": 2, "b": 3, "c": 4}
jq ´map(., .)´ [1,2] => [1,1,2,2]
jq ´map_values(. // empty)´ {"a": null, "b": true, "c": false} => {"b":true}
pick(pathexps) Belirtilen yol ifadeleri (path expressions) dizisi tarafından tanımlanan girdi nesnesi veya dizisinin izdüşümünü (projection) üretir; öyle ki eğer p bu tanımlamalardan herhangi biriyse, o halde (. | p), (. | pick(pathexps) | p) ile aynı değere çözümlenecektir. Diziler için negatif indeksler ve .[m:n] tanımlamaları kullanılmamalıdır.
jq ´pick(.a, .b.c, .x)´ {"a": 1, "b": {"c": 2, "d": 3}, "e": 4} => {"a":1,"b":{"c":2},"x":null}
jq ´pick(.[2], .[0], .[0])´ [1,2,3,4] => [1,null,3]
path(path_expression)
. içindeki verilen yol ifadesinin dizi gösterimlerini çıktı olarak verir. Çıktılar, dize (nesne anahtarları) ve/veya sayılardan (dizi indeksleri) oluşan dizilerdir.
Yol ifadeleri, .a gibi, ama aynı zamanda .[] gibi jq ifadeleridir. İki tür yol ifadesi vardır: tam olarak eşleşebilenler ve eşleşemeyenler. Örneğin, .a.b.c tam eşleşen bir yol ifadesiyken, .a[].b öyle değildir.
Eğer . değeri null, bir dizi veya bir nesne ise, path(exact_path_expression) yol ifadesi . içinde var olmasa bile o yol ifadesinin dizi gösterimini üretecektir.
path(pattern), eğer yollar . içinde mevcutsa, şablonla (pattern) eşleşen yolların dizi gösterimlerini üretecektir.
Yol ifadelerinin normal ifadelerden farklı olmadığına dikkat edin. path(..|select(type=="boolean")) ifadesi, . içindeki boolean değerlere giden tüm yolları ve yalnızca bu yolları çıktı olarak verir.
jq ´path(.a[0].b)´ null => ["a",0,"b"]
jq ´[path(..)]´ {"a":[{"b":1}]} => [[],["a"],["a",0],["a",0,"b"]]
del(path_expression)
Yerleşik (builtin) del fonksiyonu, bir nesneden bir anahtarı ve buna karşılık gelen değeri kaldırır.
jq ´del(.foo)´ {"foo": 42, "bar": 9001, "baz": 42} => {"bar": 9001, "baz": 42}
jq ´del(.[1, 2])´ ["foo", "bar", "baz"] => ["foo"]
getpath(PATHS)
Yerleşik getpath fonksiyonu, PATHS içindeki her bir yolda bulunan . içindeki değerleri çıktı olarak verir.
jq ´getpath(["a","b"])´ null => null
jq ´[getpath(["a","b"], ["a","c"])]´ {"a":{"b":0, "c":1}} => [0, 1]
setpath(PATHS; VALUE)
Yerleşik setpath fonksiyonu, . içindeki PATHS yollarını VALUE değerine ayarlar.
jq ´setpath(["a","b"]; 1)´ null => {"a": {"b": 1}}
jq ´setpath(["a","b"]; 1)´ {"a":{"b":0}} => {"a": {"b": 1}}
jq ´setpath([0,"a"]; 1)´ null => [{"a":1}]
delpaths(PATHS)
Yerleşik delpaths fonksiyonu, . içindeki PATHS yollarını siler. PATHS, her bir yolun dize ve sayılardan oluşan bir dizi olduğu bir yollar dizisi olmalıdır.
jq ´delpaths([["a","b"]])´ {"a":{"b":1},"x":{"y":2}} => {"a":{},"x":{"y":2}}
to_entries, from_entries, with_entries(f)
Bu fonksiyonlar, bir nesne ile anahtar-değer çiftlerinden oluşan bir dizi arasında dönüşüm sağlar. Eğer to_entries fonksiyonuna bir nesne iletilirse, girdideki her k: v girdisi için çıktı dizisi {"key": k, "value": v} elemanını içerir.
from_entries bu dönüşümün tersini yapar ve with_entries(f), bir nesnenin tüm anahtarları ve değerleri üzerinde bir işlem gerçekleştirmek için kullanışlı olan to_entries | map(f) | from_entries ifadesinin kısaltmasıdır. from_entries fonksiyonu anahtar olarak "key", "Key", "name", "Name", "value" ve "Value" kelimelerini kabul eder.
jq ´to_entries´ {"a": 1, "b": 2} => [{"key":"a", "value":1}, {"key":"b", "value":2}]
jq ´from_entries´ [{"key":"a", "value":1}, {"key":"b", "value":2}] => {"a": 1, "b": 2}
jq ´with_entries(.key |= "KEY_" + .)´ {"a": 1, "b": 2} => {"KEY_a": 1, "KEY_b": 2}
select(boolean_expression)
select(f) fonksiyonu, eğer f o girdi için true döndürürse girdisini değiştirmeden üretir, aksi takdirde hiçbir çıktı üretmez.
Listeleri filtrelemek için kullanışlıdır: [1,2,3] | map(select(. >= 2)) size [2,3] değerini verecektir.
jq ´map(select(. >= 2))´ [1,5,3,0,7] => [5,3,7]
jq ´.[] | select(.id == "second")´ [{"id": "first", "val": 1}, {"id": "second", "val": 2}] => {"id": "second", "val": 2}
arrays, objects, iterables, booleans, numbers, normals, finites, strings, nulls, values, scalars Bu yerleşik filtreler, sırasıyla yalnızca dizi (array), nesne (object), yinelenebilir (iterable - dizi veya nesne), boolean, sayı (number), normal sayı, sonlu sayı (finite number), dize (string), null, null olmayan değerler ve yinelenemeyen (non-iterable - skaler) girdileri seçer.
jq ´.[]|numbers´ [[],{},1,"foo",null,true,false] => 1
empty
empty hiçbir sonuç döndürmez. Kesinlikle hiçbir şey. Null bile değil.
Zaman zaman oldukça kullanışlıdır. İhtiyacınız olduğunda bunu zaten anlarsınız :)
jq ´1, empty, 2´ null => 1, 2
jq ´[1,2,empty,3]´ null => [1,2,3]
error, error(message)
Girdi değeriyle veya argüman olarak verilen mesajla bir hata üretir. Hatalar try/catch ile yakalanabilir; aşağıya bakın.
jq ´try error catch .´ "error message" => "error message"
jq ´try error("invalid value: (.)") catch .´ 42 => "invalid value: 42"
halt jq programını başka hiçbir çıktı vermeden durdurur. jq, 0 çıkış koduyla (exit status) sonlanacaktır.
halt_error, halt_error(exit_code) jq programını başka hiçbir çıktı vermeden durdurur. Girdi, stderr üzerinde ham çıktı olarak (yani dizeler çift tırnak işaretlerine sahip olmayacaktır) herhangi bir süsleme olmaksızın, hatta yeni satır bile olmadan yazdırılacaktır.
Belirtilen exit_code (varsayılan olarak 5) jq'nun çıkış kodu olacaktır.
Örneğin, "Error: something went wrong\n"|halt_error(1).
$loc
Değer olarak $__loc__ ifadesinin bulunduğu dosya adını ve satır numarasını içeren, "file" ve "line" anahtarlarına sahip bir nesne üretir.
jq ´try error("($loc)") catch .´
null
=> "{"file":"
paths, paths(node_filter)
paths, girdisindeki tüm öğelerin yollarını çıktı olarak verir (yalnızca . nesnesinin kendisini temsil eden boş listeyi çıktı olarak vermez).
paths(f), f koşulunun true olduğu tüm değerlerin yollarını çıktı olarak verir. Yani, paths(type == "number") tüm sayısal değerlerin yollarını çıktı olarak verir.
jq ´[paths]´ [1,[[],{"a":2}]] => [[0],[1],[1,0],[1,1],[1,1,"a"]]
jq ´[paths(type == "number")]´ [1,[[],{"a":2}]] => [[0],[1,1,"a"]]
add
add filtresi girdi olarak bir dizi alır ve çıktı olarak dizinin öğelerinin birbirine eklenmesiyle elde edilen sonucu üretir. Bu, girdi dizisinin öğelerinin türlerine bağlı olarak toplanmış, birleştirilmiş (concatenated) veya bir araya getirilmiş (merged) olmaları anlamına gelebilir; kurallar yukarıda açıklanan + operatörü kuralları ile aynıdır.
Eğer girdi boş bir dizi ise, add null döndürür.
jq ´add´ ["a","b","c"] => "abc"
jq ´add´ [1, 2, 3] => 6
jq ´add´ [] => null
any, any(condition), any(generator; condition)
any filtresi girdi olarak bir boolean değerler dizisi alır ve eğer dizinin öğelerinden herhangi biri true ise çıktı olarak true üretir.
Eğer girdi boş bir dizi ise, any false döndürür.
any(condition) biçimi, belirtilen koşulu girdi dizisinin öğelerine uygular.
any(generator; condition) biçimi, belirtilen koşulu verilen üretecin (generator) tüm çıktılarına uygular.
jq ´any´ [true, false] => true
jq ´any´ [false, false] => false
jq ´any´ [] => false
all, all(condition), all(generator; condition)
all filtresi girdi olarak bir boolean değerler dizisi alır ve eğer dizinin tüm öğeleri true ise çıktı olarak true üretir.
all(condition) biçimi, belirtilen koşulu girdi dizisinin öğelerine uygular.
all(generator; condition) biçimi, belirtilen koşulu verilen üretecin tüm çıktılarına uygular.
Eğer girdi boş bir dizi ise, all true döndürür.
jq ´all´ [true, false] => false
jq ´all´ [true, true] => true
jq ´all´ [] => true
flatten, flatten(depth)
flatten filtresi girdi olarak içiçe geçmiş dizilerden oluşan bir dizi alır ve orijinal dizinin içindeki tüm dizilerin özyinelemeli (recursively) olarak kendi değerleriyle değiştirildiği düz bir dizi üretir. Düzleştirilecek iç içe geçme seviyesi sayısını belirtmek için buna bir argüman iletebilirsiniz.
flatten(2), flatten gibidir ancak yalnızca en fazla iki seviye derinliğe kadar düzleştirme yapar.
jq ´flatten´ [1, [2], [[3]]] => [1, 2, 3]
jq ´flatten(1)´ [1, [2], [[3]]] => [1, 2, [3]]
jq ´flatten´ [[]] => []
jq ´flatten´ [{"foo": "bar"}, [{"foo": "baz"}]] => [{"foo": "bar"}, {"foo": "baz"}]
range(upto), range(from; upto), range(from; upto; by)
range fonksiyonu bir sayı aralığı üretir. range(4; 10), 4'ten (dahil) 10'a (hariç) kadar 6 sayı üretir. Sayılar ayrı çıktılar halinde üretilir. Aralığı bir dizi olarak elde etmek için [range(4; 10)] ifadesini kullanın.
Tek argümanlı biçim, 0'dan verilen sayıya kadar 1'er artışla sayılar üretir.
İki argümanlı biçim, from değerinden upto değerine kadar 1'er artışla sayılar üretir.
Üç argümanlı biçim, from değerinden upto değerine kadar by artış miktarı ile sayılar üretir.
jq ´range(2; 4)´ null => 2, 3
jq ´[range(2; 4)]´ null => [2,3]
jq ´[range(4)]´ null => [0,1,2,3]
jq ´[range(0; 10; 3)]´ null => [0,3,6,9]
jq ´[range(0; 10; -1)]´ null => []
jq ´[range(0; -5; -1)]´ null => [0,-1,-2,-3,-4]
floor
floor fonksiyonu, sayısal girdisinin taban değerini (aşağı yuvarlanmış halini) döndürür.
jq ´floor´ 3.14159 => 3
sqrt
sqrt fonksiyonu, sayısal girdisinin karekökünü döndürür.
jq ´sqrt´ 9 => 3
tonumber
tonumber fonksiyonu, girdisini bir sayı olarak çözümler. Doğru biçimlendirilmiş dizeleri sayısal karşılıklarına dönüştürür, sayıları olduğu gibi bırakır ve diğer tüm girdilerde hata verir.
jq ´.[] | tonumber´ [1, "1"] => 1, 1
tostring
tostring fonksiyonu, girdisini bir dize olarak yazdırır. Dizeler değiştirilmeden bırakılır ve diğer tüm değerler JSON kodlu hale getirilir (JSON-encoded).
jq ´.[] | tostring´ [1, "1", [1]] => "1", "1", "[1]"
type
type fonksiyonu, argümanının türünü; null, boolean, number, string, array veya object türlerinden biri olacak şekilde bir dize olarak döndürür.
jq ´map(type)´ [0, false, [], {}, null, "hello"] => ["number", "boolean", "array", "object", "null", "string"]
infinite, nan, isinfinite, isnan, isfinite, isnormal
Bazı aritmetik işlemler sonsuzluk (infinity) ve "sayı değil" (NaN) değerleri üretebilir. Yerleşik isinfinite filtresi, girdisi sonsuz ise true döndürür. Yerleşik isnan filtresi, girdisi bir NaN ise true döndürür. Yerleşik infinite filtresi, pozitif bir sonsuzluk değeri döndürür. Yerleşik nan filtresi, bir NaN döndürür. Yerleşik isnormal filtresi, girdisi normal bir sayı ise true döndürür.
Sıfıra bölme işleminin bir hata ürettiğine dikkat edin.
Şu anda sonsuzluklar, NaN'lar ve alt-normal (sub-normal) sayılar üzerinde çalışan çoğu aritmetik işlem hata üretmemektedir.
jq ´.[] | (infinite * .) < 0´ [-1, 1] => true, false
jq ´infinite, nan | type´ null => "number", "number"
sort, sort_by(path_expression)
sort fonksiyonu, girdi olarak mutlaka bir dizi (array) almalı ve bu girdiyi sıralamalıdır. Değerler aşağıdaki sıraya göre sıralanır:
• null
• false
• true
• sayılar
• dizeler, alfabetik sırada (Unicode kod noktası değerine göre)
• diziler, sözlüksel (lexical) sırada
• nesneler
Nesnelerin sıralanması biraz karmaşıktır: İlk olarak, anahtar kümeleri karşılaştırılarak (sıralı düzendeki diziler olarak) karşılaştırılırlar ve eğer anahtarları eşitse, değerler anahtar anahtar karşılaştırılır.
sort_by, bir nesnenin belirli bir alanına göre sıralama yapmak veya herhangi bir jq filtresi uygulamak için kullanılabilir. sort_by(f) karşılaştırma işleminde iki öğe üzerinde f ifadesinin sonucunu karşılaştırarak çalışır. f birden fazla değer ürettiğinde, ilk olarak ilk değerleri karşılaştırır, eğer ilk değerler eşitse ikinci değerleri karşılaştırır ve bu şekilde devam eder.
jq ´sort´ [8,3,null,6] => [null,3,6,8]
jq ´sort_by(.foo)´ [{"foo":4, "bar":10}, {"foo":3, "bar":10}, {"foo":2, "bar":1}] => [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":4, "bar":10}]
jq ´sort_by(.foo, .bar)´ [{"foo":4, "bar":10}, {"foo":3, "bar":20}, {"foo":2, "bar":1}, {"foo":3, "bar":10}] => [{"foo":2, "bar":1}, {"foo":3, "bar":10}, {"foo":3, "bar":20}, {"foo":4, "bar":10}]
group_by(path_expression)
group_by(.foo) girdi olarak bir dizi alır, aynı .foo alanına sahip öğeleri ayrı diziler halinde gruplar ve bu dizilerin tümünü, .foo alanının değerine göre sıralanmış daha büyük bir dizinin öğeleri olarak üretir.
.foo yerine yalnızca bir alana erişim değil, herhangi bir jq ifadesi kullanılabilir. Sıralama düzeni, yukarıdaki sort fonksiyonunda açıklanan sıralama düzeniyle aynıdır.
jq ´group_by(.foo)´ [{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}] => [[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]
min, max, min_by(path_exp), max_by(path_exp) Girdi dizisinin en küçük (minimum) veya en büyük (maximum) öğesini bulur.
min_by(path_exp) ve max_by(path_exp) fonksiyonları, incelenecek belirli bir alanı veya özelliği belirtmenize olanak tanır; örneğin min_by(.foo) en küçük foo alanına sahip nesneyi bulur.
jq ´min´ [5,4,2,7] => 2
jq ´max_by(.foo)´ [{"foo":1, "bar":14}, {"foo":2, "bar":3}] => {"foo":2, "bar":3}
unique, unique_by(path_exp)
unique fonksiyonu girdi olarak bir dizi alır ve yinelenenlerin kaldırıldığı, sıralanmış düzende aynı öğelerden oluşan bir dizi üretir.
unique_by(path_exp) fonksiyonu, argümanın uygulanmasıyla elde edilen her bir değer için yalnızca tek bir öğe tutacaktır. Bunu, group (yani group_by) tarafından üretilen her gruptan bir öğe alarak yeni bir dizi oluşturmak gibi düşünebilirsiniz.
jq ´unique´ [1,2,5,3,5,3,1,3] => [1,2,3,5]
jq ´unique_by(.foo)´ [{"foo": 1, "bar": 2}, {"foo": 1, "bar": 3}, {"foo": 4, "bar": 5}] => [{"foo": 1, "bar": 2}, {"foo": 4, "bar": 5}]
jq ´unique_by(length)´ ["chunky", "bacon", "kitten", "cicada", "asparagus"] => ["bacon", "chunky", "asparagus"]
reverse Bu fonksiyon bir diziyi tersine çevirir.
jq ´reverse´ [1,2,3,4] => [4,3,2,1]
contains(element)
contains(b) filtresi, eğer b girdi içinde tamamen barındırılıyorsa true üretir. Eğer bir B dizesi A dizesinin bir alt dizesi (substring) ise, B dizesi A içinde barındırılıyor demektir. Eğer B dizisindeki tüm öğeler A dizisindeki herhangi bir öğe tarafından barındırılıyorsa, B dizisi A dizisinde barındırılıyor demektir. Eğer B nesnesindeki tüm değerler, A nesnesinde aynı anahtara sahip değerlerin içinde barındırılıyorsa, B nesnesi A nesnesinde barındırılıyor demektir. Diğer tüm türlerin, eğer birbirlerine eşitlerse birbirlerini barındırdıkları varsayılır.
jq ´contains("bar")´ "foobar" => true
jq ´contains(["baz", "bar"])´ ["foobar", "foobaz", "blarp"] => true
jq ´contains(["bazzzzz", "bar"])´ ["foobar", "foobaz", "blarp"] => false
jq ´contains({foo: 12, bar: [{barp: 12}]})´ {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} => true
jq ´contains({foo: 12, bar: [{barp: 15}]})´ {"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]} => false
indices(s)
. içinde s ifadesinin geçtiği indeksleri içeren bir dizi çıktı olarak verir. Girdi bir dizi olabilir; bu durumda eğer s de bir dizi ise, çıktı olarak verilecek indeksler, . içindeki tüm öğelerin s içindekilerle eşleştiği indeksler olacaktır.
jq ´indices(", ")´ "a,b, cd, efg, hijk" => [3,7,12]
jq ´indices(1)´ [0,1,2,1,3,1,4] => [1,3,5]
jq ´indices([1,2])´ [0,1,2,3,1,4,2,5,1,2,6,7] => [1,8]
index(s), rindex(s)
Girdide s ifadesinin ilk (index) veya son (rindex) geçtiği yerin indeksini çıktı olarak verir.
jq ´index(", ")´ "a,b, cd, efg, hijk" => 3
jq ´index(1)´ [0,1,2,1,3,1,4] => 1
jq ´index([1,2])´ [0,1,2,3,1,4,2,5,1,2,6,7] => 1
jq ´rindex(", ")´ "a,b, cd, efg, hijk" => 12
jq ´rindex(1)´ [0,1,2,1,3,1,4] => 5
jq ´rindex([1,2])´ [0,1,2,3,1,4,2,5,1,2,6,7] => 8
inside
inside(b) filtresi, eğer girdi tamamen b içinde barındırılıyorsa true üretir. Esasen, contains filtresinin tersine çevrilmiş (inversed) versiyonudur.
jq ´inside("foobar")´ "bar" => true
jq ´inside(["foobar", "foobaz", "blarp"])´ ["baz", "bar"] => true
jq ´inside(["foobar", "foobaz", "blarp"])´ ["bazzzzz", "bar"] => false
jq ´inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})´ {"foo": 12, "bar": [{"barp": 12}]} => true
jq ´inside({"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]})´ {"foo": 12, "bar": [{"barp": 15}]} => false
startswith(str)
Eğer . verilen dize (string) argümanı ile başlıyorsa true çıktısı verir.
jq ´[.[]|startswith("foo")]´ ["fo", "foo", "barfoo", "foobar", "barfoob"] => [false, true, false, true, false]
endswith(str)
Eğer . verilen dize argümanı ile bitiyorsa true çıktısı verir.
jq ´[.[]|endswith("foo")]´ ["foobar", "barfoo"] => [false, true]
combinations, combinations(n)
Girdi dizisindeki dizilerin öğelerinin tüm kombinasyonlarını çıktı olarak verir. Eğer bir n argümanı verilirse, girdi dizisinin n kez yinelenmesinin tüm kombinasyonlarını çıktı olarak verir.
jq ´combinations´ [[1,2], [3, 4]] => [1, 3], [1, 4], [2, 3], [2, 4]
jq ´combinations(2)´ [0, 1] => [0, 0], [0, 1], [1, 0], [1, 1]
ltrimstr(str) Eğer girdi belirtilen ön ek (prefix) dizesiyle başlıyorsa, bu ön ek kaldırılmış şekilde girdiyi çıktı olarak verir.
jq ´[.[]|ltrimstr("foo")]´ ["fo", "foo", "barfoo", "foobar", "afoo"] => ["fo","","barfoo","bar","afoo"]
rtrimstr(str) Eğer girdi belirtilen son ek (suffix) dizesiyle bitiyorsa, bu son ek kaldırılmış şekilde girdiyi çıktı olarak verir.
jq ´[.[]|rtrimstr("foo")]´ ["fo", "foo", "barfoo", "foobar", "foob"] => ["fo","","bar","foobar","foob"]
explode Bir girdi dizesini, dizeye ait kod noktası (codepoint) sayılarından oluşan bir diziye dönüştürür.
jq ´explode´ "foobar" => [102,111,111,98,97,114]
implode
explode fonksiyonunun tersidir.
jq ´implode´ [65, 66, 67] => "ABC"
split(str) Bir girdi dizesini ayırıcı (separator) argümana göre böler.
split, iki argümanla çağrıldığında düzenli ifade (regex) eşleşmelerine göre de bölme yapabilir (aşağıdaki düzenli ifadeler bölümüne bakın).
jq ´split(", ")´ "a, b,c,d, e, " => ["a","b,c,d","e",""]
join(str)
Girdi olarak verilen öğeler dizisini, argümanı ayırıcı olarak kullanarak birleştirir. split fonksiyonunun tersidir: yani, herhangi bir girdi dizesi üzerinde split("foo") | join("foo") çalıştırmak, söz konusu girdi dizesini döndürür.
Girdideki sayılar ve boolean değerler dizelere dönüştürülür. Null değerler boş dizeler olarak kabul edilir. Girdideki diziler ve nesneler desteklenmez.
jq ´join(", ")´ ["a","b,c,d","e"] => "a, b,c,d, e"
jq ´join(" ")´ ["a",1,2.3,true,null,false] => "a 1 2.3 true false"
ascii_downcase, ascii_upcase Girdi dizesinin alfabetik karakterlerinin (a-z ve A-Z) belirtilen büyüklüğe/küçüklüğe dönüştürüldüğü bir kopyasını üretir.
jq ´ascii_upcase´ "useful but not for é" => "USEFUL BUT NOT FOR é"
while(cond; update)
while(cond; update) fonksiyonu, cond koşulu false olana kadar . değerine tekrar tekrar bir güncelleme (update) uygulamanıza olanak tanır.
while(cond; update) fonksiyonunun dahili olarak özyinelemeli (recursive) bir jq fonksiyonu olarak tanımlandığına dikkat edin. Eğer update her bir girdi için en fazla bir çıktı üretiyorsa, while içindeki özyinelemeli çağrılar ek bellek tüketmeyecektir. Aşağıdaki gelişmiş konulara bakın.
jq ´[while(.<100; .*2)]´ 1 => [1,2,4,8,16,32,64]
repeat(exp) repeat(exp) fonksiyonu, bir hata oluşana kadar exp ifadesini . üzerine tekrar tekrar uygulamanızı sağlar.
repeat(exp) fonksiyonunun dahili olarak özyinelemeli (recursive) bir jq fonksiyonu şeklinde tanımlandığını unutmayın. Eğer exp her bir girdi için en fazla bir çıktı üretiyorsa, repeat içerisindeki özyinelemeli çağrılar ek bellek tüketmeyecektir. Aşağıdaki gelişmiş konulara bakın.
jq ´[repeat(.*2, error)?]´ 1 => [2]
until(cond; next) until(cond; next) fonksiyonu, cond doğru olana kadar, başlangıçta . üzerine, ardından kendi çıktısı üzerine next ifadesini tekrar tekrar uygulamanızı sağlar. Örneğin, bu bir faktöriyel fonksiyonu uygulamak için kullanılabilir (aşağıya bakın).
until(cond; next) fonksiyonunun dahili olarak özyinelemeli bir jq fonksiyonu şeklinde tanımlandığını unutmayın. Eğer next her bir girdi için en fazla bir çıktı üretiyorsa, until() içerisindeki özyinelemeli çağrılar ek bellek tüketmeyecektir. Aşağıdaki gelişmiş konulara bakın.
jq ´[.,1]|until(.[0] < 1; [.[0] - 1, .[1] * .[0]])|.[1]´ 4 => 24
recurse(f), recurse, recurse(f; condition) recurse(f) fonksiyonu, özyinelemeli bir yapı içinde arama yapmanıza ve tüm seviyelerden ilgilendiğiniz verileri çıkarmanıza olanak tanır. Girdinizin bir dosya sistemini temsil ettiğini varsayalım:
{"name": "/", "children": [ {"name": "/bin", "children": [ {"name": "/bin/ls", "children": []}, {"name": "/bin/sh", "children": []}]}, {"name": "/home", "children": [ {"name": "/home/stephen", "children": [ {"name": "/home/stephen/jq", "children": []}]}]}]}
Şimdi mevcut tüm dosya adlarını çıkarmak istediğinizi varsayalım. .name, .children[].name, .children[].children[].name ve benzeri değerleri almanız gerekir. Bunu şununla yapabilirsiniz:
recurse(.children[]) | .name
Herhangi bir argüman olmadan çağrıldığında, recurse ifadesi recurse(.[]?) ifadesine eşdeğerdir.
recurse(f) fonksiyonu, recurse(f; true) ile tamamen aynıdır ve özyineleme derinliği hakkında endişe duymadan kullanılabilir.
recurse(f; condition), hesaplanan değer koşulu karşıladığı sürece . yayarak (emit ederek) başlayan ve ardından sırasıyla .|f, .|f|f, .|f|f|f, ... yayan bir üreteçtir (generator). Örneğin, en azından teoride tüm tam sayıları üretmek için recurse(.+1; true) yazılabilir.
f her bir girdi için en fazla tek bir çıktı ürettiği sürece, recurse içindeki özyinelemeli çağrılar ek bellek tüketmeyecektir.
jq ´recurse(.foo[])´ {"foo":[{"foo": []}, {"foo":[{"foo":[]}]}]} => {"foo":[{"foo":[]},{"foo":[{"foo":[]}]}]}, {"foo":[]}, {"foo":[{"foo":[]}]}, {"foo":[]}
jq ´recurse´ {"a":0,"b":[1]} => {"a":0,"b":[1]}, 0, [1], 1
jq ´recurse(. * .; . < 20)´ 2 => 2, 4, 16
walk(f) walk(f) fonksiyonu, f fonksiyonunu girdi varlığının her bileşenine özyinelemeli olarak uygular. Bir diziyle (array) karşılaşıldığında, f önce onun elemanlarına, ardından dizinin kendisine uygulanır; bir nesneyle (object) karşılaşıldığında, f önce tüm değerlere, ardından nesneye uygulanır. Pratikte f, aşağıdaki örneklerde gösterildiği gibi genellikle girdisinin türünü test eder. İlk örnek, diziler dizisinin elemanlarını dizinin kendisini işlemeden önce işlemenin faydasını vurgulamaktadır. İkinci örnek, girdi içindeki tüm nesnelerin tüm anahtarlarının değişiklik için nasıl değerlendirilebileceğini göstermektedir.
jq ´walk(if type == "array" then sort else . end)´ [[4, 1, 7], [8, 5, 2], [3, 6, 9]] => [[1,4,7],[2,5,8],[3,6,9]]
jq ´walk( if type == "object" then with_entries( .key |= sub( "^_+"; "") ) else . end )´ [ { "_a": { "__b": 2 } } ] => [{"a":{"b":2}}]
$JQ_BUILD_CONFIGURATION Bu yerleşik bağlama (binding), jq yürütülebilir dosyasının derleme yapılandırmasını (build configuration) gösterir. Değerinin belirli bir formatı yoktur, ancak en azından ./configure komut satırı argümanları olması beklenir ve gelecekte kullanılan derleme araçlarının sürüm dizelerini içerecek şekilde zenginleştirilebilir.
Bunun komut satırında --arg ve ilgili seçeneklerle geçersiz kılınabileceğini (override edilebileceğini) unutmayın.
$ENV, env $ENV, jq programı başladığında ayarlanmış olan çevre değişkenlerini (environment variables) temsil eden bir nesnedir.
env, jq'nun mevcut çevresini temsil eden bir nesne çıktı olarak verir.
Şu anda çevre değişkenlerini ayarlamak için yerleşik bir işlev bulunmamaktadır.
jq ´$ENV.PAGER´ null => "less"
jq ´env.PAGER´ null => "less"
transpose Muhtemelen düzensiz (jagged) bir matrisi (diziler dizisini) devrik hale getirir (transpose eder). Sonucun her zaman dikdörtgen olması için satırlar null değerleri ile doldurulur.
jq ´transpose´ [[1], [2,3]] => [[1,2],[null,3]]
bsearch(x) bsearch(x) girdi dizisinde x için ikili arama (binary search) yapar. Eğer girdi sıralıysa ve x değerini içeriyorsa, bsearch(x) onun dizideki indeksini döndürür; aksi takdirde, eğer dizi sıralıysa, diziye x değerinin ix indeksinde eklenmesinden sonra dizinin hala sıralı kalacağı bir ekleme noktası olan ix değerine göre (-1 - ix) döndürür. Eğer dizi sıralı değilse, bsearch(x) muhtemelen hiçbir ilgi çekmeyecek bir tam sayı döndürecektir.
jq ´bsearch(0)´ [0,1] => 0
jq ´bsearch(0)´ [1,2,3] => -1
jq ´bsearch(4) as $ix | if $ix < 0 then .[-(1+$ix)] = 4 else . end´ [1,2,3] => [1,2,3,4]
Dize enterpolasyonu: (exp) Bir dizenin (string) içinde, ters eğik çizgiden sonra parantez içine bir ifade yerleştirebilirsiniz. İfade ne döndürürse döndürsün dizeye enterpole edilecektir (eklenecektir).
jq ´"The input was (.), which is one less than (.+1)"´ 42 => "The input was 42, which is one less than 43"
JSON'a/JSON'dan dönüştürme tojson ve fromjson yerleşikleri, sırasıyla değerleri JSON metinleri olarak döker veya JSON metinlerini değerlere ayrıştırır. tojson yerleşiği tostring'den farklıdır; tostring dizeleri üzerinde değişiklik yapmadan döndürürken, tojson dizeleri JSON dizeleri olarak kodlar.
jq ´[.[]|tostring]´ [1, "foo", ["foo"]] => ["1","foo","["foo"]"]
jq ´[.[]|tojson]´ [1, "foo", ["foo"]] => ["1",""foo"","["foo"]"]
jq ´[.[]|tojson|fromjson]´ [1, "foo", ["foo"]] => [1,"foo",["foo"]]
Dizeleri biçimlendirme ve kaçış karakterleri (escaping) @foo sözdizimi, URL'ler, HTML veya XML gibi bir dildeki belgeler vb. oluşturmak için yararlı olan dizeleri biçimlendirmek ve kaçış karakteriyle korumak amacıyla kullanılır. @foo kendi başına bir filtre olarak kullanılabilir, olası kaçış yöntemleri şunlardır:
@text:
tostring fonksiyonunu çağırır, detaylar için bu fonksiyona bakın.
@json:
Girdiyi JSON olarak serileştirir.
@html:
<>&´" karakterlerini <, >, &, ', " varlık eşdeğerlerine eşleyerek HTML/XML kaçış (escaping) uygular.
@uri:
Tüm rezerve edilmiş URI karakterlerini bir %XX dizisine eşleyerek yüzde kodlaması (percent-encoding) uygular.
@csv:
Girdi bir dizi olmalıdır ve dizeler için çift tırnak kullanılarak ve tırnak işaretleri tekrarlanarak kaçış karakteri eklenmiş şekilde CSV olarak işlenir.
@tsv:
Girdi bir dizi olmalıdır ve TSV (sekme ile ayrılmış değerler) olarak işlenir. Her bir girdi dizisi tek bir satır olarak yazdırılacaktır. Alanlar tek bir sekme (ASCII 0x09) ile ayrılır. Satır besleme (ASCII 0x0a), satır başı (ASCII 0x0d), sekme (ASCII 0x09) ve ters eğik çizgi (ASCII 0x5c) girdi karakterleri sırasıyla \n, \r, \t, \ kaçış dizileri olarak çıktıya verilecektir.
@sh:
Girdi, POSIX kabuk komut satırında kullanıma uygun şekilde kaçış karakteriyle korunur. Girdi bir dizi ise, çıktı boşlukla ayrılmış bir dizi dize olacaktır.
@base64:
Girdi, RFC 4648 tarafından belirtildiği gibi base64'e dönüştürülür.
@base64d:
@base64'ün tersidir, girdi RFC 4648 tarafından belirtildiği gibi çözülür (decode edilir). Not: Çözülen dize UTF-8 değilse, sonuçlar tanımsızdır.
Bu sözdizimi, kullanışlı bir şekilde dize enterpolasyonu ile birleştirilebilir. Bir @foo belirtecini bir dize sabit değeriyle takip edebilirsiniz. Dize sabit değerinin içeriği kaçış karakterleriyle korunmayacaktır. Ancak, bu dize sabit değerinin içinde yapılan tüm enterpolasyonlar kaçış karakterleriyle korunacaktır. Örneğin,
@uri "https://www.google.com/search?q=\(.search)"
girdisi {"search":"what is jq?"} için aşağıdaki çıktıyı üretecektir:
"https://www.google.com/search?q=what%20is%20jq%3F"
URL'deki eğik çizgilerin, soru işaretinin vb. dize sabit değerinin bir parçası oldukları için kaçış karakterleriyle korunmadığını unutmayın.
jq ´@html´ "This works if x < y" => "This works if x < y"
jq ´@sh "echo (.)"´ "O´Hara´s Ale" => "echo ´O´\´´Hara´\´´s Ale´"
jq ´@base64´ "This is a message" => "VGhpcyBpcyBhIG1lc3NhZ2U="
jq ´@base64d´ "VGhpcyBpcyBhIG1lc3NhZ2U=" => "This is a message"
Tarihler jq, bazı üst seviye ve alt seviye yerleşik işlevlerle bazı temel tarih işleme yetenekleri sağlar. Tüm durumlarda bu yerleşikler özel olarak UTC zaman dilimiyle çalışır.
fromdateiso8601 yerleşik işlevi, ISO 8601 biçimindeki tarih-saat değerlerini Unix başlangıcından (Unix epoch, 1970-01-01T00:00:00Z) bu yana geçen saniye sayısına ayrıştırır. todateiso8601 yerleşik işlevi ise bunun tersini yapar.
fromdate yerleşik işlevi tarih-saat dizelerini ayrıştırır. Şu anda fromdate yalnızca ISO 8601 tarih-saat dizelerini desteklemektedir, ancak gelecekte tarih-saat dizelerini daha fazla biçimde ayrıştırmayı deneyecektir.
todate yerleşik işlevi, todateiso8601 için bir takma addır (alias).
now yerleşik işlevi, Unix başlangıcından (Unix epoch) bu yana geçen saniye cinsinden mevcut zamanı çıktı olarak verir.
C kütüphanesi zaman fonksiyonlarına yönelik alt seviye jq arayüzleri de sağlanmıştır: strptime, strftime, strflocaltime, mktime, gmtime ve localtime. strptime ve strftime tarafından kullanılan biçim dizeleri için ana bilgisayar işletim sisteminizin belgelerine bakın. Not: Bunlar, özellikle yerelleştirme (localization) işlevleri açısından jq içinde mutlaka kararlı arayüzler değildir.
gmtime yerleşik işlevi, Unix başlangıcından (Unix epoch) bu yana geçen saniye sayısını alır ve Greenwich Ortalama Zamanı'nın (Greenwich Mean Time) "parçalanmış zaman" (broken down time) temsilini şu sırayla sayı dizisi olarak çıktı verir: yıl, ay (sıfır tabanlı), ayın günü (bir tabanlı), günün saati, saatin dakikası, dakikanın saniyesi, haftanın günü ve yılın günü -- aksi belirtilmedikçe hepsi bir tabanlıdır. Haftanın günü sayısı, bazı sistemlerde 1 Mart 1900'den önceki veya 31 Aralık 2099'dan sonraki tarihler için yanlış olabilir.
localtime yerleşik işlevi gmtime yerleşik işlevi gibi çalışır, ancak yerel saat dilimi ayarını kullanır.
mktime yerleşik işlevi, gmtime ve strptime tarafından çıktı olarak verilen "parçalanmış zaman" (broken down time) temsillerini alır.
strptime(fmt) yerleşik işlevi, fmt argümanıyla eşleşen girdi dizelerini ayrıştırır. Çıktı, gmtime tarafından tüketilen ve mktime tarafından çıktı olarak verilen "parçalanmış zaman" temsilindedir.
strftime(fmt) yerleşik işlevi bir zamanı (GMT) verilen biçimde biçimlendirir. strflocaltime ise yerel saat dilimi ayarını kullanarak aynısını yapar.
strptime ve strftime için biçim dizeleri tipik C kütüphanesi belgelerinde açıklanmıştır. ISO 8601 tarih-saat biçim dizesi "%Y-%m-%dT%H:%M:%SZ" şeklindedir.
jq, bazı sistemlerde bu tarih işlevlerinin bir kısmını veya tamamını desteklemeyebilir. Özellikle, strptime(fmt) için %u ve %j belirteçleri macOS üzerinde desteklenmemektedir.
jq ´fromdate´ "2015-03-05T23:51:47Z" => 1425599507
jq ´strptime("%Y-%m-%dT%H:%M:%SZ")´ "2015-03-05T23:51:47Z" => [2015,2,5,23,51,47,4,63]
jq ´strptime("%Y-%m-%dT%H:%M:%SZ")|mktime´ "2015-03-05T23:51:47Z" => 1425599507
SQL Stili Operatörler jq, birkaç SQL stili operatör sağlar.
INDEX(stream; index_expression):
Bu yerleşik işlev, anahtarları verilen akıştan (stream) alınan her bir değere uygulanan belirtilen indeks ifadesiyle hesaplanan bir nesne üretir.
JOIN($idx; stream; idx_expr; join_expr):
Bu yerleşik işlev, verilen akıştan gelen değerleri verilen indeksle birleştirir (join eder). İndeksin anahtarları, verilen indeks ifadesinin verilen akıştaki her bir değere uygulanmasıyla hesaplanır. Akıştaki değerin ve indeksteki karşılık gelen değerin bir dizisi, her bir sonucu üretmek için verilen birleştirme (join) ifadesine beslenir.
JOIN($idx; stream; idx_expr):
JOIN($idx; stream; idx_expr; .) ile aynıdır.
JOIN($idx; idx_expr):
Bu yerleşik işlev, girdi olarak alınan . değerini verilen indeksle birleştirir ve indeks anahtarını hesaplamak için verilen indeks ifadesini . üzerine uygular. Birleştirme (join) işlemi yukarıda açıklandığı gibidir.
IN(s):
Bu yerleşik işlev, eğer . verilen akışta (stream) görünüyorsa true, aksi takdirde false çıktısı verir.
IN(source; s):
Bu yerleşik işlev, kaynak akışındaki herhangi bir değer ikinci akışta görünüyorsa true, aksi takdirde false çıktısı verir.
builtins Tüm yerleşik fonksiyonların listesini name/arity (ad/argüman sayısı) formatında döndürür. Aynı ada sahip ancak farklı argüman sayılarına sahip fonksiyonlar ayrı fonksiyonlar olarak kabul edildiğinden, all/0, all/1 ve all/2 değerlerinin hepsi listede mevcut olacaktır.
Koşullar ve Karşılaştırmalar
==, != ´a == b´ ifadesi, a ve b'nin değerlendirilme sonuçları eşitse (yani eşdeğer JSON değerlerini temsil ediyorlarsa) ´true´, aksi takdirde ´false´ üretecektir. Özellikle, dizeler asla sayılara eşit kabul edilmez. JSON nesnelerinin eşitliğini kontrol ederken anahtarların sıralaması önemsizdir. JavaScript geçmişiniz varsa, jq'nun == operatörünün JavaScript'in "kesin eşitlik" (strict equality) operatörü olan === gibi olduğunu lütfen unutmayın.
!= operatörü "eşit değil" anlamına gelir ve ´a != b´ ifadesi ´a == b´ ifadesinin zıt değerini döndürür.
jq ´. == false´ null => false
jq ´. == {"b": {"d": (4 + 1e-20), "c": 3}, "a":1}´ {"a":1, "b": {"c": 3, "d": 4}} => true
jq ´.[] == 1´ [1, 1.0, "1", "banana"] => true, true, false, false
if-then-else-end if A then B else C end, A eğer false veya null dışında bir değer üretirse B ile aynı şekilde hareket eder, aksi takdirde C ile aynı şekilde hareket eder.
if A then B end, if A then B else . end ile aynıdır. Yani else dalı isteğe bağlıdır ve eksik olduğunda . ile aynı anlama gelir. Bu durum, sonlandırıcı else dalı olmayan elif için de geçerlidir.
false veya null değerlerini kontrol etmek, JavaScript veya Python'da bulunandan daha basit bir "doğruluk" (truthiness) kavramıdır, ancak bu bazen istediğiniz koşul hakkında daha açık olmanız gerekeceği anlamına gelir. Örneğin bir dizenin boş olup olmadığını if .name then A else B end kullanarak test edemezsiniz; bunun yerine if .name == "" then A else B end gibi bir şeye ihtiyacınız olacaktır.
Eğer A koşulu birden fazla sonuç üretirse, B, false veya null olmayan her bir sonuç için bir kez değerlendirilir ve C, her bir false veya null için bir kez değerlendirilir.
elif A then B sözdizimi kullanılarak bir if ifadesine daha fazla durum eklenebilir.
jq ´if . == 0 then "zero" elif . == 1 then "one" else "many" end´ 2 => "many"
, >=, <=, < Karşılaştırma operatörleri >, >=, <=, < (sırasıyla) sol argümanlarının sağ argümanlarından büyük, büyük veya eşit, küçük veya eşit ya da küçük olup olmadığını döndürür.
Sıralama, yukarıda sort için açıklananla aynıdır.
jq ´. < 5´ 2 => true
and, or, not jq normal Boole operatörleri olan and, or, not ifadelerini destekler. Bunlar if ifadeleriyle aynı doğruluk standardına sahiptir - false ve null "yanlış değerler" olarak kabul edilir ve diğer her şey bir "doğru değer"dir.
Bu operatörlerden birinin işleneni (operand) birden fazla sonuç üretirse, operatörün kendisi her bir girdi için bir sonuç üretecektir.
not aslında bir operatörden ziyade yerleşik bir fonksiyondur, bu nedenle özel bir sözdizimi yerine .foo and .bar | not ifadesinde olduğu gibi şeylerin yönlendirilebileceği (pipe edilebileceği) bir filtre olarak çağrılır.
Bu üçü yalnızca true ve false değerlerini üretir ve bu nedenle bir koşulu değerlendirmek yerine iki değer arasından seçim yapan yaygın Perl/Python/Ruby tarzı "null_olabilecek_değer veya varsayılan" kullanımı yerine yalnızca gerçek Boole işlemleri için kullanışlıdır. Eğer iki değer arasından seçim yapan bu "or" biçimini kullanmak istiyorsanız, aşağıdaki // operatörüne bakın.
jq ´42 and "a string"´ null => true
jq ´(true, false) or false´ null => true, false
jq ´(true, true) and (true, false)´ null => true, false, true, false
jq ´[true, false | not]´ null => [false, true]
Alternatif operatör: // // operatörü, sol tarafındaki false veya null olmayan tüm değerleri üretir. Eğer sol taraf false veya null dışında hiçbir değer üretmezse, // sağ tarafındaki tüm değerleri üretir.
a // b formundaki bir filtre, a'nın false veya null olmayan tüm sonuçlarını üretir. Eğer a hiçbir sonuç üretmezse veya false ya da null dışında hiçbir sonuç üretmezse, a // b ifadesi b'nin sonuçlarını üretir.
Bu varsayılan değerleri sağlamak için kullanışlıdır: Girdide .foo öğesi yoksa .foo // 1 ifadesi 1 olarak değerlendirilecektir. Python'da or operatörünün bazen kullanım şekline benzer (jq'nun or operatörü kesinlikle Boole işlemleri için ayrılmıştır).
Not: some_generator // defaults_here ile some_generator | . // defaults_here aynı şey değildir. İkincisi sol tarafın tüm false olmayan ve null olmayan değerleri için varsayılan değerler üretirken, birincisi bunu yapmaz. Öncelik kuralları bunu kafa karıştırıcı hale getirebilir. Örneğin, false, 1 // 2 ifadesinde // operatörünün sol tarafı false, 1 değil 1'dir -- false, 1 // 2 ifadesi false, (1 // 2) ile aynı şekilde ayrıştırılır. (false, null, 1) | . // 42 ifadesinde // operatörünün sol tarafı her zaman yalnızca tek bir değer üreten . iken, (false, null, 1) // 42 ifadesinde sol taraf üç değerli bir üreteçtir (generator) ve false ile null dışında bir değer ürettiği için varsayılan 42 üretilmez.
jq ´empty // 42´ null => 42
jq ´.foo // 42´ {"foo": 19} => 19
jq ´.foo // 42´ {} => 42
jq ´(false, null, 1) // 42´ null => 1
jq ´(false, null, 1) | . // 42´ null => 42, 42, 1
try-catch Hatalar try EXP catch EXP kullanılarak yakalanabilir. İlk ifade yürütülür ve başarısız olursa, ikincisi hata mesajıyla birlikte yürütülür. Varsa, işleyicinin (handler) çıktısı, denenecek ifadenin çıktısıymış gibi çıktı olarak verilir.
try EXP formu, istisna işleyicisi (exception handler) olarak empty kullanır.
jq ´try .a catch ". is not an object"´ true => ". is not an object"
jq ´[.[]|try .a]´ [{}, true, {"a":1}] => [null, 1]
jq ´try error("some exception") catch .´ true => "some exception"
Kontrol yapılarından çıkma try/catch'in kullanışlı bir amacı, reduce, foreach, while gibi kontrol yapılarından çıkmaktır.
Örneğin:
Bir ifadeyi hata olarak "break" oluşturana kadar tekrarlayın,
ardından hatayı yeniden oluşturmadan tekrarlamayı durdurun.
Ancak yakalanan hata "break" değilse, onu yeniden oluşturun.
try repeat(exp) catch if .=="break" then empty else error
jq, "çıkmak" (break) veya "(geri) gitmek" (go back to) için adlandırılmış sözcüksel etiketler (lexical labels) sözdizimine sahiptir:
label $out | ... break $out ...
break $label_name ifadesi, programın en yakınındaki (soldaki) label $label_name ifadesinin empty üretmiş gibi davranmasına neden olur.
break ve ilgili etiket arasındaki ilişki sözdükseldir (lexical): etiketin break konumundan "görünür" olması gerekir.
Örneğin, bir reduce yapısından çıkmak için:
label $out | reduce .[] as $item (null; if .==false then break $out else ... end)
Aşağıdaki jq programı bir sözdizimi hatası üretir:
break $out
çünkü hiçbir $out etiketi görünür değildir.
Hata Bastırma / İsteğe Bağlı Operatör: ? EXP? olarak kullanılan ? operatörü, try EXP için bir kısayoldur.
jq ´[.[] | .a?]´ [{}, true, {"a":1}] => [null, 1]
jq ´[.[] | tonumber?]´ ["1", "invalid", "3", 4] => [1, 3, 4]
Düzenli İfadeler (Regular Expressions)
jq, PHP, TextMate, Sublime Text vb. uygulamaların da yaptığı gibi Oniguruma düzenli ifade kütüphanesini kullanır, bu nedenle buradaki açıklama jq'ya özgü niteliklere odaklanacaktır.
Oniguruma, düzenli ifadelerin birkaç farklı türünü (flavor) destekler, bu nedenle jq'nun "Perl NG" (adlandırılmış gruplara sahip Perl) türünü kullandığını bilmek önemlidir.
jq regex filtreleri, aşağıdaki kalıplardan biri kullanılarak çalıştırılabilecek şekilde tanımlanmıştır:
STRING | FILTER(REGEX) STRING | FILTER(REGEX; FLAGS) STRING | FILTER([REGEX]) STRING | FILTER([REGEX, FLAGS])
burada:
• STRING, REGEX ve FLAGS, jq dizeleridir ve jq dize enterpolasyonuna tabidir;
• REGEX, dize enterpolasyonundan sonra geçerli bir düzenli ifade olmalıdır;
• FILTER, aşağıda açıklandığı gibi test, match veya capture işlevlerinden biridir.
REGEX'in bir JSON dizesi olarak değerlendirilmesi gerektiğinden, bir düzenli ifade oluşturmak için gereken bazı karakterlerin kaçış karakterleriyle yazılması gerekir. Örneğin, boşluk karakterini belirten \s düzenli ifadesi "\s" olarak yazılmalıdır.
FLAGS, desteklenen bayraklardan (flags) bir veya daha fazından oluşan bir dizedir:
• g - Genel arama (yalnızca ilkini değil, tüm eşleşmeleri bulur)
• i - Büyük/küçük harfe duyarsız arama
• m - Çoklu satır modu (. yeni satır karakterleriyle eşleşir)
• n - Boş eşleşmeleri yoksay
• p - Hem s hem de m modları etkindir
• s - Tek satır modu (^ -> \A, $ -> \Z)
• l - Mümkün olan en uzun eşleşmeleri bul
• x - Genişletilmiş regex formatı (boşlukları ve yorumları yoksay)
x bayrağıyla bir boşluğu eşleştirmek için \s kullanın, örneğin:
jq -n ´"a b" | test("a\sb"; "x")´
Bazı bayrakların REGEX içinde de belirtilebileceğini unutmayın, örneğin:
jq -n ´("test", "TEst", "teST", "TEST") | test("(?i)te(?-i)st")´
şuna değerlendirilir: true, true, false, false.
test(val), test(regex; flags) match gibidir, ancak eşleşme nesnelerini (match objects) döndürmez, yalnızca regex'in girdiyle eşleşip eşleşmediğine dair true veya false döndürür.
jq ´test("foo")´ "foo" => true
jq ´.[] | test("a b c # spaces are ignored"; "ix")´ ["xabcd", "ABC"] => true, true
match(val), match(regex; flags) match, bulduğu her bir eşleşme için bir nesne çıktı olarak verir. Eşleşmeler aşağıdaki alanlara sahiptir:
• offset - girdinin başlangıcından itibaren UTF-8 kod noktaları (codepoints) cinsinden uzaklık
• length - eşleşmenin UTF-8 kod noktaları cinsinden uzunluğu
• string - eşleşen dize
• captures - yakalama gruplarını (capturing groups) temsil eden nesnelerden oluşan bir dizi.
Yakalama grubu nesneleri aşağıdaki alanlara sahiptir:
• offset - girdinin başlangıcından itibaren UTF-8 kod noktaları (codepoints) cinsinden uzaklık
• length - bu yakalama grubunun UTF-8 kod noktaları cinsinden uzunluğu
• string - yakalanan dize
• name - yakalama grubunun adı (veya isimsiz ise null)
Hiçbir şeyle eşleşmeyen yakalama grupları -1 değerinde bir offset döndürür.
jq ´match("(abc)+"; "g")´ "abc abc" => {"offset": 0, "length": 3, "string": "abc", "captures": [{"offset": 0, "length": 3, "string": "abc", "name": null}]}, {"offset": 4, "length": 3, "string": "abc", "captures": [{"offset": 4, "length": 3, "string": "abc", "name": null}]}
jq ´match("foo")´ "foo bar foo" => {"offset": 0, "length": 3, "string": "foo", "captures": []}
jq ´match(["foo", "ig"])´ "foo bar FOO" => {"offset": 0, "length": 3, "string": "foo", "captures": []}, {"offset": 8, "length": 3, "string": "FOO", "captures": []}
jq ´match("foo (?
jq ´[ match("."; "g")] | length´ "abc" => 3
capture(val), capture(regex; flags) Adlandırılmış yakalamaları (named captures), her bir yakalamanın adı anahtar ve eşleşen dize karşılık gelen değer olacak şekilde bir JSON nesnesinde toplar.
jq ´capture("(?[a-z]+)-(?
scan(regex), scan(regex; flags) Varsa belirtilen bayraklara uygun olarak, girdinin regex ile eşleşen ve çakışmayan (non-overlapping) alt dizelerinin bir akışını yayar. Eşleşme yoksa akış boştur. Her bir girdi dizesi için tüm eşleşmeleri yakalamak amacıyla [ expr ] kalıbını kullanın, örneğin [ scan(regex) ].
jq ´scan("c")´ "abcdefabc" => "c", "c"
split(regex; flags) Bir girdi dizesini her regex eşleşmesinde böler.
Geriye dönük uyumluluk için, tek bir argümanla çağrıldığında, split bir regex üzerinde değil, bir dize üzerinde bölme yapar.
jq ´split(", *"; null)´ "ab,cd, ef" => ["ab","cd","ef"]
splits(regex), splits(regex; flags) Bunlar split karşılıklarıyla aynı sonuçları sağlar, ancak dizi yerine bir akış olarak sunar.
jq ´splits(", *")´ "ab,cd, ef, gh" => "ab", "cd", "ef", "gh"
sub(regex; tostring), sub(regex; tostring; flags) Girdi dizesindeki regex'in ilk eşleşmesini, enterpolasyondan sonra tostring ile değiştirerek elde edilen dizeyi yayar. tostring bir jq dizesi veya her biri adlandırılmış yakalamalara referanslar içerebilen bu tür dizelerden oluşan bir akış olmalıdır. Adlandırılmış yakalamalar, aslında tostring'e bir JSON nesnesi olarak (capture tarafından oluşturulduğu gibi) sunulur, dolayısıyla "x" adlı yakalanan bir değişkene yapılan referans şu biçimi alacaktır: "(.x)".
jq ´sub("[^a-z]*(?
jq ´[sub("(?.)"; "(.a|ascii_upcase)", "(.a|ascii_downcase)")]´ "aB" => ["AB","aB"]
gsub(regex; tostring), gsub(regex; tostring; flags) gsub, sub gibidir ancak regex'in çakışmayan tüm oluşumları enterpolasyondan sonra tostring ile değiştirilir. İkinci argüman bir jq dizesi akışıysa, o zaman gsub buna karşılık gelen bir JSON dizesi akışı üretecektir.
jq ´gsub("(?
jq ´[gsub("p"; "a", "b")]´ "p" => ["a","b"]
Gelişmiş Özellikler
Değişkenler çoğu programlama dilinde mutlak bir gerekliliktir, ancak jq'da "ileri düzey bir özellik" konumuna indirgenmiştir.
Çoğu dilde değişkenler, veriyi bir yerden bir yere aktarmanın tek yoludur. Bir değer hesaplarsanız ve bunu birden fazla kez kullanmak isterseniz, onu bir değişkende saklamanız gerekir. Bir değeri programın başka bir bölümüne aktarmak için programın o bölümünün, veriyi yerleştireceği bir değişken (fonksiyon parametresi, nesne üyesi veya başka bir şey olarak) tanımlaması gerekir.
En büyük kullanım alanı jq'nun standart kütüphanesini tanımlamak olan bir özellik olsa da, jq'da fonksiyonlar tanımlamak da mümkündür (aslında map ve select gibi birçok jq fonksiyonu jq ile yazılmıştır).
jq, oldukça güçlü ancak biraz karmaşık olan indirgeme (reduction) operatörlerine sahiptir. Bunlar da yine çoğunlukla dahili olarak, jq'nun standart kütüphanesinin bazı yararlı kısımlarını tanımlamak için kullanılır.
Başlangıçta belirgin olmayabilir, ancak jq tamamen üreteçler (generator) (evet, diğer dillerde de sıkça bulunanlar gibi) hakkındadır. Üreteçlerle çalışmayı kolaylaştırmak için bazı yardımcı araçlar sunulmuştur.
Minimum düzeyde bir I/O (Giriş/Çıkış) desteği (standart girdiden JSON okuma ve standart çıktıya JSON yazmanın yanı sıra) mevcuttur.
Son olarak, bir modül/kütüphane sistemi bulunmaktadır.
Değişken / Sembolik Bağlama Operatörü: ... as $identifier | ... In jq, all filters have an input and an output, so manual plumbing is not necessary to pass a value from one part of a program to the next. Many expressions, for instance a + b, pass their input to two distinct subexpressions (here a and b are both passed the same input), so variables aren´t usually necessary in order to use a value twice.
Örneğin, bir sayı dizisinin ortalama değerini hesaplamak çoğu dilde birkaç değişken gerektirir; en azından diziyi tutmak için bir tane, belki her bir öğe için bir tane veya bir döngü sayacı için bir tane. jq'da bu işlem sadece add / length şeklindedir; add ifadesine dizi verilir ve dizinin toplamını üretir, length ifadesine dizi verilir ve dizinin uzunluğunu üretir.
Dolayısıyla, jq'daki çoğu problemi çözmek için değişken tanımlamaktan genellikle daha temiz bir yol vardır. Yine de bazen işleri kolaylaştırdıkları için jq, ifade as $variable kullanarak değişken tanımlamanıza olanak tanır. Tüm değişken isimleri $ ile başlar. Dizi ortalaması alma örneğinin biraz daha çirkin bir versiyonu şöyledir:
length as $array_length | add / $array_length
Değişken kullanmanın hayatımızı gerçekten kolaylaştırdığı bir durum bulmak için daha karmaşık bir probleme ihtiyacımız olacak.
"author" ve "title" alanlarına sahip bir blog yazıları dizimiz ve yazar kullanıcı adlarını gerçek isimlerle eşleştirmek için kullanılan başka bir nesnemiz olduğunu varsayalım. Girdimiz şöyledir:
{"posts": [{"title": "First post", "author": "anon"}, {"title": "A well-written article", "author": "person1"}], "realnames": {"anon": "Anonymous Coward", "person1": "Person McPherson"}}
Yazar alanında gerçek ismin yer aldığı yazıları üretmek istiyoruz, şu şekilde:
{"title": "First post", "author": "Anonymous Coward"} {"title": "A well-written article", "author": "Person McPherson"}
Yazar kullanıcı adlarını ararken daha sonra başvurabilmek amacıyla realnames nesnesini saklamak için bir $names değişkeni kullanırız:
.realnames as $names | .posts[] | {title, author: $names[.author]}
exp as $x | ... ifadesi şu anlama gelir: exp ifadesinin her bir değeri için, boru hattının (pipeline) geri kalanını orijinal girdinin tamamıyla ve $x bu değere ayarlanmış olarak çalıştır. Dolayısıyla as, bir nevi foreach döngüsü gibi işlev görür.
Tıpkı {foo} ifadesinin {foo: .foo} yazmanın kolay bir yolu olması gibi, {$foo} da {foo: $foo} yazmanın kolay bir yoludur.
Girdinin yapısıyla eşleşen bir şablon sağlanarak tek bir as ifadesi kullanılarak birden fazla değişken tanımlanabilir (bu durum "yapı bozma" veya "destructuring" olarak bilinir):
. as {realnames: $names, posts: [$first, $second]} | ...
Dizi şablonlarındaki değişken tanımlamaları (örneğin, . as [$first, $second]), sırasıyla sıfırıncı indeksteki öğeden başlayarak dizinin öğelerine bağlanır. Dizi şablonu öğesi için ilgili indekste bir değer bulunmadığında, o değişkene null bağlanır.
Değişkenlerin kapsamı (scope), kendilerini tanımlayan ifadenin geri kalanını kapsar, dolayısıyla
.realnames as $names | (.posts[] | {title, author: $names[.author]})
çalışacaktır, ancak
(.realnames as $names | .posts[]) | {title, author: $names[.author]}
çalışmayacaktır.
Programlama dili teorisyenleri için, jq değişkenlerinin sözcüksel kapsamlı (lexically-scoped) bağlamalar olduğunu söylemek daha doğrudur. Özellikle bir bağlamanın değerini değiştirmenin hiçbir yolu yoktur; sadece aynı isme sahip yeni bir bağlama oluşturulabilir, ancak bu yeni bağlama eskisinin görünür olduğu yerde görünür olmayacaktır.
jq ´.bar as $x | .foo | . + $x´ {"foo":10, "bar":200} => 210
jq ´. as $i|[(.*2|. as $i| $i), $i]´ 5 => [10,5]
jq ´. as [$a, $b, {c: $c}] | $a + $b + $c´ [2, 3, {"c": 4, "d": 5}] => 9
jq ´.[] as [$a, $b] | {a: $a, b: $b}´ [[0], [0, 1], [2, 1, 0]] => {"a":0,"b":null}, {"a":0,"b":1}, {"a":2,"b":1}
Yapı Bozma Alternatif Operatörü: ?// Yapı bozma alternatif operatörü, birkaç farklı biçimden birini alabilen bir girdiyi yapı bozmaya tabi tutmak için kısa ve öz bir mekanizma sağlar.
Kendileriyle ilişkili kaynakların ve olayların bir listesini döndüren bir API'miz olduğunu ve her kaynak için ilk olayın user_id ve zaman damgasını (timestamp) almak istediğimizi varsayalım. API (XML'den beceriksizce dönüştürüldüğü için), olayları yalnızca kaynağın birden fazla olayı varsa bir dizi içine saracaktır:
{"resources": [{"id": 1, "kind": "widget", "events": {"action": "create", "user_id": 1, "ts": 13}}, {"id": 2, "kind": "widget", "events": [{"action": "create", "user_id": 1, "ts": 14}, {"action": "destroy", "user_id": 1, "ts": 15}]}]}
Bu yapısal değişikliği basitçe ele almak için yapı bozma alternatif operatörünü kullanabiliriz:
.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$user_id, $ts}]} | {$user_id, $kind, $id, $ts}
Veya girdinin bir değerler dizisi mi yoksa bir nesne mi olduğundan emin değilsek:
.[] as [$id, $kind, $user_id, $ts] ?// {$id, $kind, $user_id, $ts} | ...
Her bir alternatifin aynı değişkenlerin tamamını tanımlaması gerekmez, ancak adlandırılmış tüm değişkenler sonraki ifade için kullanılabilir olacaktır. Başarılı olan alternatifte eşleşmeyen değişkenler null olacaktır:
.resources[] as {$id, $kind, events: {$user_id, $ts}} ?// {$id, $kind, events: [{$first_user_id, $first_ts}]} | {$user_id, $first_user_id, $kind, $id, $ts, $first_ts}
Ek olarak, sonraki ifade bir hata döndürürse, alternatif operatörü bir sonraki bağlamayı denemeye çalışacaktır. Son alternatif sırasında meydana gelen hatalar doğrudan iletilir.
[[3]] | .[] as [$a] ?// [$b] | if $a != null then error("err: ($a)") else {$a,$b} end
jq ´.[] as {$a, $b, c: {$d, $e}} ?// {$a, $b, c: [{$d, $e}]} | {$a, $b, $d, $e}´ [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] => {"a":1,"b":2,"d":3,"e":4}, {"a":1,"b":2,"d":3,"e":4}
jq ´.[] as {$a, $b, c: {$d}} ?// {$a, $b, c: [{$e}]} | {$a, $b, $d, $e}´ [{"a": 1, "b": 2, "c": {"d": 3, "e": 4}}, {"a": 1, "b": 2, "c": [{"d": 3, "e": 4}]}] => {"a":1,"b":2,"d":3,"e":null}, {"a":1,"b":2,"d":null,"e":4}
jq ´.[] as [$a] ?// [$b] | if $a != null then error("err: ($a)") else {$a,$b} end´ [[3]] => {"a":null,"b":3}
Fonksiyonları Tanımlama "def" sözdizimini kullanarak bir filtreye isim verebilirsiniz:
def increment: . + 1;
O andan itibaren, increment tıpkı yerleşik (builtin) bir fonksiyon gibi bir filtre olarak kullanılabilir (aslında birçok yerleşik fonksiyon bu şekilde tanımlanır). Bir fonksiyon argüman alabilir:
def map(f): [.[] | f];
Argümanlar değer olarak değil, filtreler (argümansız fonksiyonlar) olarak aktarılır. Aynı argümana farklı girdilerle birden fazla kez başvurulabilir (burada f, girdi dizisinin her bir öğesi için çalıştırılır). Bir fonksiyonun argümanları, değer argümanlarından ziyade geri çağrım (callback) gibi çalışır. Bunu anlamak önemlidir. Şunu göz önünde bulundurun:
def foo(f): f|f; 5|foo(.*2)
Sonuç 20 olacaktır çünkü f ifadesi .*2'dir; f'in ilk çağrılması sırasında . değeri 5 olacak, ikinci kez çağrıldığında ise 10 (5 * 2) olacaktır, dolayısıyla sonuç 20 olacaktır. Fonksiyon argümanları filtredir ve filtreler çağrıldıklarında bir girdi beklerler.
Basit fonksiyonları tanımlamak için değer-argümanı davranışı istiyorsanız, sadece bir değişken kullanabilirsiniz:
def addvalue(f): f as $f | map(. + $f);
Veya kısa yolu kullanabilirsiniz:
def addvalue($f): ...;
Her iki tanımla da addvalue(.foo), mevcut girdinin .foo alanını dizinin her bir öğesine ekleyecektir. addvalue(.[]) çağrısının yapılması, map(. + $f) kısmının, çağrı noktasındaki . değerinin her bir değeri için bir kez değerlendirilmesine neden olacağını unutmayın.
Aynı fonksiyon ismini kullanan birden fazla tanımlamaya izin verilir. Her yeniden tanımlama, aynı sayıda fonksiyon argümanına sahip bir önceki tanımlamanın yerini alır, ancak bu yalnızca yeniden tanımlamadan sonraki fonksiyonlardan (veya ana programdan) yapılan başvurular için geçerlidir. Ayrıca aşağıdaki kapsam belirleme (scoping) bölümüne bakın.
jq ´def addvalue(f): . + [f]; map(addvalue(.[0]))´ [[1,2],[10,20]] => [[1,2,1], [10,20,10]]
jq ´def addvalue(f): f as $x | map(. + $x); addvalue(.[0])´ [[1,2],[10,20]] => [[1,2,1,2], [10,20,1,2]]
Kapsam jq'da iki tür sembol vardır: değer bağlamaları (diğer adıyla "değişkenler") ve fonksiyonlar. Her ikisi de sözcüksel olarak kapsama alınır (scoped lexically); ifadeler yalnızca kendi "solunda" tanımlanmış olan sembollere başvurabilir. Bu kuralın tek istisnası, fonksiyonların özyinelemeli (recursive) fonksiyonlar oluşturabilmek için kendilerine başvurabilmeleridir.
Örneğin, aşağıdaki ifadede, kendi "sağında" görünür olan bir bağlama vardır, ... | .*3 as $times_three | [. + $times_three] | ..., ancak "solunda" görünür değildir. Şimdi şu ifadeyi ele alalım, ... | (.*3 as $times_three | [. + $times_three]) | ...: burada $times_three bağlaması, kapanış parantezinden sonra görünür değildir.
isempty(exp) Eğer exp hiçbir çıktı üretmiyorsa true, aksi takdirde false döndürür.
jq ´isempty(empty)´ null => true
jq ´isempty(.[])´ [] => true
jq ´isempty(.[])´ [1,2,3] => false
limit(n; exp) limit fonksiyonu, exp ifadesinden en fazla n adet çıktı ayıklar.
jq ´[limit(3;.[])]´ [0,1,2,3,4,5,6,7,8,9] => [0,1,2]
first(expr), last(expr), nth(n; expr) first(expr) ve last(expr) fonksiyonları, sırasıyla expr ifadesinden ilk ve son değerleri ayıklar.
nth(n; expr) fonksiyonu, expr tarafından çıktı olarak verilen n. değeri ayıklar. nth(n; expr) fonksiyonunun negatif n değerlerini desteklemediğini unutmayın.
jq ´[first(range(.)), last(range(.)), nth(./2; range(.))]´ 10 => [0,9,5]
first, last, nth(n) first ve last fonksiyonları, . konumundaki herhangi bir diziden ilk ve son değerleri ayıklar.
nth(n) fonksiyonu, . konumundaki herhangi bir dizinin n. değerini ayıklar.
jq ´[range(.)]|[first, last, nth(5)]´ 10 => [0,9,5]
reduce reduce sözdizimi, bir ifadenin tüm sonuçlarını tek bir yanıtta biriktirerek birleştirmenize olanak tanır. Biçimi reduce EXP as $var (INIT; UPDATE) şeklindedir. Örnek olarak, bu ifadeye [1,2,3] değerini geçireceğiz:
reduce .[] as $item (0; . + $item)
.[] ifadesinin ürettiği her bir sonuç için, 0 girdi değerinden başlayarak çalışan toplamı biriktirmek üzere . + $item çalıştırılır. Bu örnekte .[] ifadesi 1, 2 ve 3 sonuçlarını üretir, dolayısıyla etki şuna benzer bir şeyi çalıştırmaya benzer:
0 | 1 as $item | . + $item | 2 as $item | . + $item | 3 as $item | . + $item
jq ´reduce .[] as $item (0; . + $item)´ [1,2,3,4,5] => 15
jq ´reduce .[] as [$i,$j] (0; . + $i * $j)´ [[1,2],[3,4],[5,6]] => 44
jq ´reduce .[] as {$x,$y} (null; .x += $x | .y += [$y])´ [{"x":"a","y":1},{"x":"b","y":2},{"x":"c","y":3}] => {"x":"abc","y":[1,2,3]}
foreach foreach sözdizimi reduce sözdizimine benzer, ancak ara sonuçlar üreten limitler ve indirgeyiciler (reducer) oluşturulmasına izin vermek amacıyla tasarlanmıştır.
Biçimi foreach EXP as $var (INIT; UPDATE; EXTRACT) şeklindedir. Örnek olarak, bu ifadeye [1,2,3] değerini geçireceğiz:
foreach .[] as $item (0; . + $item; [$item, . * 2])
reduce sözdiziminde olduğu gibi, .[] ifadesinin ürettiği her bir sonuç için . + $item çalıştırılır, ancak her bir ara değer için [$item, . * 2] çalıştırılır. Bu örnekte ara değerler 1, 3 ve 6 olduğundan, foreach ifadesi [1,2], [2,6] ve [3,12] üretir. Dolayısıyla etki şuna benzer bir şeyi çalıştırmaya benzer:
0 | 1 as $item | . + $item | [$item, . * 2], 2 as $item | . + $item | [$item, . * 2], 3 as $item | . + $item | [$item, . * 2]
EXTRACT atlandığında, kimlik (identity) filtresi kullanılır. Yani, ara değerleri oldukları gibi çıktı olarak verir.
jq ´foreach .[] as $item (0; . + $item)´ [1,2,3,4,5] => 1, 3, 6, 10, 15
jq ´foreach .[] as $item (0; . + $item; [$item, . * 2])´ [1,2,3,4,5] => [1,2], [2,6], [3,12], [4,20], [5,30]
jq ´foreach .[] as $item (0; . + 1; {index: ., $item})´ ["foo", "bar", "baz"] => {"index":1,"item":"foo"}, {"index":2,"item":"bar"}, {"index":3,"item":"baz"}
Özyineleme Yukarıda açıklandığı gibi, recurse özyineleme kullanır ve herhangi bir jq fonksiyonu özyinelemeli olabilir. Yerleşik while fonksiyonu da özyineleme cinsinden uygulanmıştır.
Kuyruk çağrıları (tail calls) özyinelemeli çağrının solundaki ifade son değerini çıktı olarak verdiğinde optimize edilir. Pratikte bu, özyinelemeli çağrının solundaki ifadenin her girdi için birden fazla çıktı üretmemesi gerektiği anlamına gelir.
Örneğin:
def recurse(f): def r: ., (f | select(. != null) | r); r;
def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while;
def repeat(exp): def _repeat: exp, _repeat; _repeat;
Üreteçler ve yineleyiciler Bazı jq operatörleri ve fonksiyonları, üreteçlere sahip diğer programlama dillerinde beklenebileceği gibi, her girdi için sıfır, bir veya daha fazla değer üretebilmeleri bakımından aslında üreteçlerdir (generator). Örneğin .[], girdisindeki (bir dizi veya nesne olmalıdır) tüm değerleri üretir, range(0; 10) 0 ile 10 arasındaki tam sayıları üretir ve bu böyle devam eder.
Virgül operatörü bile bir üreteçtir; önce virgülün solundaki ifade tarafından üretilen değerleri, ardından virgülün sağındaki ifade tarafından üretilen değerleri üretir.
Yerleşik empty fonksiyonu, sıfır çıktı üreten bir üreteçtir. Yerleşik empty fonksiyonu, kendisinden önceki üreteç ifadesine geri izleme (backtrack) yapar.
Tüm jq fonksiyonları, yalnızca yerleşik üreteçleri kullanarak üreteç haline gelebilir. Yalnızca özyineleme ve virgül operatörünü kullanarak yeni üreteçler oluşturmak da mümkündür. Özyinelemeli çağrılar "kuyruk konumunda" (in tail position) ise üreteç verimli olacaktır. Aşağıdaki örnekte, _range fonksiyonunun kendisine yaptığı özyinelemeli çağrı kuyruk konumundadır. Örnek, üç ileri düzey konuyu sergilemektedir: kuyruk özyinelemesi (tail recursion), üreteç oluşturma (generator construction) ve alt fonksiyonlar.
jq ´def range(init; upto; by): def _range: if (by > 0 and . < upto) or (by < 0 and . > upto) then ., ((.+by)|_range) else . end; if by == 0 then init else init|_range end | select((by > 0 and . < upto) or (by < 0 and . > upto)); range(0; 10; 3)´ null => 0, 3, 6, 9
jq ´def while(cond; update): def _while: if cond then ., (update | _while) else empty end; _while; [while(.<100; .*2)]´ 1 => [1,2,4,8,16,32,64]
Matematik
jq şu anda yalnızca IEEE754 çift duyarlıklı (64-bit) kayan noktalı sayı desteğine sahiptir.
- gibi basit aritmetik operatörlerin yanı sıra jq, C matematik kütüphanesindeki çoğu standart matematik fonksiyonuna da sahiptir. Tek bir girdi argümanı alan C matematik fonksiyonları (örneğin sin()) sıfır argümanlı jq fonksiyonları olarak mevcuttur. İki girdi argümanı alan C matematik fonksiyonları (örneğin pow()), . değerini yok sayan iki argümanlı jq fonksiyonları olarak mevcuttur. Üç girdi argümanı alan C matematik fonksiyonları, . değerini yok sayan üç argümanlı jq fonksiyonları olarak mevcuttur.
Standart matematik fonksiyonlarının kullanılabilirliği, işletim sisteminizdeki ve C matematik kütüphanenizdeki karşılık gelen matematik fonksiyonlarının kullanılabilirliğine bağlıdır. Kullanılamayan matematik fonksiyonları tanımlanacak ancak bir hata üretecektir.
Tek girdili C matematik fonksiyonları: acos acosh asin asinh atan atanh cbrt ceil cos cosh erf erfc exp exp10 exp2 expm1 fabs floor gamma j0 j1 lgamma log log10 log1p log2 logb nearbyint pow10 rint round significand sin sinh sqrt tan tanh tgamma trunc y0 y1.
İki girdili C matematik fonksiyonları: atan2 copysign drem fdim fmax fmin fmod frexp hypot jn ldexp modf nextafter nexttoward pow remainder scalb scalbln yn.
Üç girdili C matematik fonksiyonları: fma.
Bunların her biri hakkında daha fazla bilgi için sisteminizin kılavuzuna (manual) bakın.
I/O Şu anda jq'nun I/O için minimal desteği vardır; bu destek çoğunlukla girdilerin ne zaman okunacağının kontrol edilmesi biçimindedir. Bunun için, jq'nun kendisiyle aynı kaynaklardan (örneğin stdin, komut satırında adı belirtilen dosyalar) okuma yapan iki yerleşik fonksiyon olan input ve inputs sunulmuştur. Bu iki yerleşik fonksiyon ve jq'nun kendi okuma eylemleri birbiriyle harmanlanabilir. Bir girdinin dolaylı olarak okunmasını önlemek için genellikle null girdi seçeneği -n ile birlikte kullanılırlar.
İki yerleşik fonksiyon minimal çıktı yetenekleri sağlar: debug ve stderr. (Bir jq programının çıktı değerlerinin her zaman stdout üzerinde JSON metinleri olarak çıktısının alındığını unutmayın.) debug yerleşik fonksiyonu, libjq C API'sini kullanan ancak jq yürütülebilir dosyasının kendisi olmayan yürütülebilir dosyalar için olduğu gibi uygulamaya özel davranışlara sahip olabilir. stderr yerleşik fonksiyonu, girdisini ek bir süsleme olmaksızın, hatta satır sonu karakteri bile eklemeden, ham (raw) modda stderr'e verir.
Çoğu jq yerleşik fonksiyonu referansal olarak şeffaftır (referentially transparent) ve sabit girdilere uygulandığında sabit ve tekrarlanabilir değer akışları üretir. Bu durum I/O yerleşik fonksiyonları için geçerli değildir.
input Bir adet yeni girdi çıktı olarak verir.
input kullanırken genellikle jq'yu -n komut satırı seçeneğiyle çağırmanın gerekli olacağını, aksi takdirde ilk varlığın kaybolacağını unutmayın.
echo 1 2 3 4 | jq ´[., input]´ # [1,2] [3,4]
inputs Kalan tüm girdileri tek tek çıktı olarak verir.
Bu, öncelikle bir programın girdileri üzerindeki indirgemeler (reduction) için kullanışlıdır. inputs kullanırken genellikle jq'yu -n komut satırı seçeneğiyle çağırmanın gerekli olduğunu, aksi takdirde ilk varlığın kaybolacağını unutmayın.
echo 1 2 3 | jq -n ´reduce inputs as $i (0; . + $i)´ # 6
debug, debug(msgs) Bu iki filtre . gibidir ancak stderr üzerinde bir veya daha fazla mesaj üretme şeklinde bir yan etkiye sahiptir.
debug filtresi tarafından üretilen mesaj şu biçimdedir:
["DEBUG:",
burada
debug(msgs) filtresi (msgs | debug | empty), . olarak tanımlanmıştır, böylece mesajın içeriğinde büyük bir esneklik sağlanırken, aynı zamanda çok satırlı hata ayıklama ifadelerinin oluşturulmasına da olanak tanınır.
Örneğin şu ifade:
1 as $x | 2 | debug("Entering function foo with $x == ($x)", .) | (.+1)
3 değerini üretecektir ancak stderr'e şu iki satır yazılacaktır:
["DEBUG:","Entering function foo with $x == 1"] ["DEBUG:",2]
stderr Girdisini hiçbir ek süsleme olmaksızın, hatta satır sonu karakteri bile eklemeden, ham ve kompakt modda stderr'e yazdırır.
input_filename Girdisi şu anda filtrelenmekte olan dosyanın adını döndürür. jq UTF-8 yerel ayarında (locale) çalışmadığı sürece bunun düzgün çalışmayacağını unutmayın.
input_line_number Girdisi şu anda filtrelenmekte olan satırın numarasını döndürür.
Akış (Streaming)
--stream seçeneği ile jq, girdi metinlerini akış biçiminde ayrıştırabilir, bu da jq programlarının büyük JSON metinlerini ayrıştırma işlemi tamamlandıktan sonra değil, hemen işlemeye başlamasına olanak tanır. 1 GB boyutunda tek bir JSON metniniz varsa, bunu akış olarak işlemek onu çok daha hızlı işlemenizi sağlayacaktır.
Ancak, jq programı girdi olarak [
Akışları işlemeyi kolaylaştırmak için birkaç yerleşik fonksiyon sunulmuştur.
Aşağıdaki örneklerde, [0,[1]] ifadesinin akışa dönüştürülmüş biçimi olan [[0],0],[[1,0],1],[[1,0]],[[1]] kullanılmıştır.
Akış biçimleri arasında [
truncate_stream(stream_expression) Girdi olarak bir sayı alır ve verilen akış ifadesinin çıktılarının solundan ilgili sayıda yol (path) öğesini kırpar.
jq ´truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]])´ 1 => [[0],2], [[0]]
fromstream(stream_expression) Akış ifadesinin çıktılarına karşılık gelen değerleri çıktı olarak verir.
jq ´fromstream(1|truncate_stream([[0],1],[[1,0],2],[[1,0]],[[1]]))´ null => [2]
tostream Yerleşik tostream fonksiyonu, girdisinin akışa dönüştürülmüş biçimini çıktı olarak verir.
jq ´. as $dot|fromstream($dot|tostream)|.==$dot´ [0,[1,{"a":1},{"b":2}]] => true
Atama (Assignment)
Atama işlemi jq'da çoğu programlama dilinden biraz daha farklı çalışır. jq bir şeyin referansları ile kopyaları arasında ayrım yapmaz; iki nesne veya dizi, "aynı nesne" veya "aynı nesne değil" şeklinde herhangi bir ek kavram olmaksızın, ya eşittir ya da eşit değildir.
Bir nesnenin dizi olan iki alanı varsa (.foo ve .bar) ve siz .foo'ya bir şey eklerseniz, daha önce .bar = .foo olarak ayarlamış olsanız bile .bar büyümeyecektir. Python, Java, Ruby, JavaScript vb. dillerde programlama yapmaya alışkınsanız, atama yapmadan önce jq'nun her nesnenin tam bir derin kopyasını (deep copy) aldığını düşünebilirsiniz (performans nedeniyle aslında bunu yapmaz, ancak genel fikir budur).
Bu, jq'da dairesel (circular) değerler (ilk öğesi kendisi olan bir dizi gibi) oluşturmanın imkansız olduğu anlamına gelir. Bu tamamen kasıtlıdır ve bir jq programının üretebileceği her şeyin JSON biçiminde temsil edilebilmesini sağlar.
jq'daki tüm atama operatörlerinin sol tarafında (LHS) yol ifadeleri (path expressions) bulunur. Sağ taraf (RHS) ise LHS yol ifadeleri tarafından adlandırılan yollara atanacak değerleri sağlar.
jq'daki değerler her zaman değiştirilemezdir (immutable). Dahili olarak atama işlemi, istenen tüm atamaların .'ya uygulandığı yeni ve yedek değerleri hesaplamak için bir indirgeme (reduction) kullanarak ve ardından değiştirilen değeri çıktı olarak vererek çalışır. Bu durum şu örnekle netleştirilebilir: {a:{b:{c:1}}} | (.a.b|=3), .. Bu örnek {"a":{"b":3}} ve {"a":{"b":{"c":1}}} çıktılarını verecektir çünkü son alt ifade olan ., değiştirilmiş değeri değil, orijinal değeri görür.
Çoğu kullanıcı, = yerine |= veya += gibi değiştirerek atama (modification assignment) operatörlerini kullanmak isteyecektir.
Atama operatörlerinin sol tarafının (LHS) . içindeki bir değere başvurduğunu unutmayın. Bu nedenle $var.foo = 1 beklendiği gibi çalışmayacaktır ($var.foo, . içinde geçerli veya yararlı bir yol ifadesi değildir); bunun yerine $var | .foo = 1 kullanın.
Ayrıca .a,.b=0 ifadesinin .a ve .b'yi ayarlamadığını, ancak (.a,.b)=0 ifadesinin her ikisini de ayarladığını unutmayın.
Update-assignment: |= Bu, "güncelleme" operatörü |='dir. Sağ tarafta bir filtre alır ve eski değeri bu ifadeden geçirerek .'nın atama yapılan özelliğinin yeni değerini hesaplar. Örneğin, (.foo, .bar) |= .+1 ifadesi, girdi değerinin foo alanına 1 eklenmiş bir foo alanına ve girdi değerinin bar alanına 1 eklenmiş bir bar alanına sahip bir nesne oluşturacaktır.
Sol taraf herhangi bir genel yol ifadesi olabilir; bkz. path().
|='nin sol tarafının . içindeki bir değere başvurduğunu unutmayın. Bu nedenle $var.foo |= . + 1 beklendiği gibi çalışmayacaktır ($var.foo, . içinde geçerli veya yararlı bir yol ifadesi değildir); bunun yerine $var | .foo |= . + 1 kullanın.
Sağ taraf hiçbir değer çıktı olarak vermezse (yani boşsa), sol taraftaki yol del(path) fonksiyonunda olduğu gibi silinecektir.
Sağ taraf birden fazla değer çıktı olarak verirse, yalnızca ilki kullanılacaktır (UYUMLULUK NOTU: jq 1.5 ve önceki sürümlerde yalnızca son değer kullanılırdı).
jq ´(..|select(type=="boolean")) |= if . then 1 else 0 end´ [true,false,[5,true,[true,[false]],false]] => [1,0,[5,1,[1,[0]],0]]
Arithmetic update-assignment: +=, -=, *=, /=, %=, //= jq, hepsi a |= . op b ifadesine eşdeğer olan a op= b biçiminde birkaç operatöre sahiptir. Dolayısıyla, += 1 değerleri artırmak için kullanılabilir ve |= . + 1 ile aynıdır.
jq ´.foo += 1´ {"foo": 42} => {"foo": 43}
Plain assignment: = Bu düz atama operatörüdür. Diğerlerinin aksine, sağ tarafın (RHS) girdisi, LHS yolundaki değer yerine sol tarafın (LHS) girdisiyle aynıdır ve RHS tarafından çıktı olarak verilen tüm değerler kullanılacaktır (aşağıda gösterildiği gibi).
Eğer ='in sağ tarafı (RHS) birden fazla değer üretiyorsa, jq bu tür her bir değer için sol taraftaki yolları o değere ayarlayacak ve ardından değiştirilmiş .'yı çıktı olarak verecektir. Örneğin, (.a,.b) = range(2) ifadesi önce {"a":0,"b":0}, ardından {"a":1,"b":1} çıktılarını verir. "Güncelleme" atama biçimleri (yukarıya bakın) bunu yapmaz.
Bu örnek, = ile |= arasındaki farkı göstermelidir:
Programlara girdi olarak {"a": {"b": 10}, "b": 20} değerini sağlayın
.a = .b
ve
.a |= .b
İlki, girdinin a alanını girdinin b alanına ayarlayacak ve {"a": 20, "b": 20} çıktısını üretecektir. İkincisi ise girdinin a alanını, a alanının b alanına ayarlayacak ve {"a": 10, "b": 20} çıktısını üretecektir.
jq ´.a = .b´ {"a": {"b": 10}, "b": 20} => {"a":20,"b":20}
jq ´.a |= .b´ {"a": {"b": 10}, "b": 20} => {"a":10,"b":20}
jq ´(.a, .b) = range(3)´ null => {"a":0,"b":0}, {"a":1,"b":1}, {"a":2,"b":2}
jq ´(.a, .b) |= range(3)´ null => {"a":0,"b":0}
Complex assignments Bir jq atamasının sol tarafında, çoğu dildekinden çok daha fazla şeye izin verilir. Sol tarafta basit alan erişimlerini zaten gördük ve dizi erişimlerinin de aynı şekilde çalışması şaşırtıcı değildir:
.posts[0].title = "JQ Manual"
Şaşırtıcı olabilecek şey, soldaki ifadenin girdi belgesindeki farklı noktalara başvuran birden fazla sonuç üretebilmesidir:
.posts[].comments |= . + ["this is great"]
Bu örnek, girdideki her bir yazının "comments" dizisine "this is great" dizesini ekler (burada girdi, yazı dizisi olan bir "posts" alanına sahip bir nesnedir).
jq, ´a = b´ gibi bir atamayla karşılaştığında, a ifadesini yürütürken girdi belgesinin bir bölümünü seçmek için izlenen "yolu" (path) kaydeder. Bu yol daha sonra, atama yürütülürken girdinin hangi kısmının değiştirileceğini bulmak için kullanılır. Bir eşittir işaretinin sol tarafında herhangi bir filtre kullanılabilir; girdiden hangi yolları seçerse, atama o konumlarda gerçekleştirilecektir.
Bu oldukça güçlü bir işlemdir. Yukarıdaki aynı "blog" girdisini kullanarak blog yazılarına bir yorum eklemek istediğimizi varsayalım. Bu sefer, yalnızca "stedolan" tarafından yazılan yazılara yorum yapmak istiyoruz. Bu yazıları daha önce açıklanan "select" fonksiyonunu kullanarak bulabiliriz:
.posts[] | select(.author == "stedolan")
Bu işlem tarafından sağlanan yollar, "stedolan"ın yazdığı yazıların her birini gösterir ve her birine daha önce yaptığımız gibi yorum yapabiliriz:
(.posts[] | select(.author == "stedolan") | .comments) |= . + ["terrible."]
Modüller
jq bir kütüphane/modül sistemine sahiptir. Modüller, adları .jq ile biten dosyalardır.
Bir program tarafından içe aktarılan modüller, varsayılan bir arama yolunda aranır (aşağıya bakın). import ve include yönergeleri, içe aktaranın bu yolu değiştirmesine olanak tanır.
Bir arama yolundaki yollar çeşitli değiştirmelere (substitution) tabidir.
~/ ile başlayan yollar için, ~ yerine kullanıcının ana dizini (home directory) konulur.
$ORIGIN/ ile başlayan yollar için, $ORIGIN yerine jq yürütülebilir dosyasının bulunduğu dizin konulur.
./ ile başlayan yollar veya . olan yollar için, . yerine dosyayı dahil eden dosyanın yolu konulur. Komut satırında verilen üst düzey programlar için mevcut dizin kullanılır.
İçe aktarma (import) yönergeleri, isteğe bağlı olarak varsayılanın sonuna eklendiği bir arama yolu belirtebilir.
Varsayılan arama yolu, -L komut satırı seçeneğine verilen arama yoludur, aksi takdirde ["~/.jq", "$ORIGIN/../lib/jq", "$ORIGIN/../lib"] şeklindedir.
Null ve boş dize yol öğeleri, arama yolu işlemeyi sonlandırır.
foo/bar göreceli yoluna sahip bir bağımlılık, verilen arama yolunda foo/bar.jq ve foo/bar/bar.jq konumlarında aranacaktır. Bu, modüllerin örneğin sürüm kontrol dosyaları, README dosyaları vb. ile birlikte bir dizine yerleştirilmesine izin vermek ve aynı zamanda tek dosyalık modüllere olanak tanımak amacıyla tasarlanmıştır.
Belirsizlikleri önlemek için aynı isme sahip ardışık bileşenlere izin verilmez (örneğin foo/foo).
Örneğin, -L$HOME/.jq ile bir foo modülü $HOME/.jq/foo.jq ve $HOME/.jq/foo/foo.jq konumlarında bulunabilir.
Eğer $HOME/.jq bir dosyaysa, ana programa dahil edilir (sourced).
import RelativePathString as NAME [
İsteğe bağlı meta veriler sabit bir jq ifadesi olmalıdır. homepage vb. anahtarlara sahip bir nesne olmalıdır. Şu anda jq, meta verilerin yalnızca search anahtarını/değerini kullanır. Meta veriler ayrıca modulemeta yerleşik fonksiyonu aracılığıyla kullanıcılara sunulur.
Meta verideki search anahtarı, mevcutsa, bir dize veya dizi değerine (diziler dizisi) sahip olmalıdır; bu, üst düzey arama yolunun önüne eklenecek arama yoludur.
include RelativePathString [
İsteğe bağlı meta veriler sabit bir jq ifadesi olmalıdır. homepage vb. anahtarlara sahip bir nesne olmalıdır. Şu anda jq, meta verilerin yalnızca search anahtarını/değerini kullanır. Meta veriler ayrıca modulemeta yerleşik fonksiyonu aracılığıyla kullanıcılara sunulur.
import RelativePathString as $NAME [
İsteğe bağlı meta veriler sabit bir jq ifadesi olmalıdır. homepage vb. anahtarlara sahip bir nesne olmalıdır. Şu anda jq, meta verilerin yalnızca search anahtarını/değerini kullanır. Meta veriler ayrıca modulemeta yerleşik fonksiyonu aracılığıyla kullanıcılara sunulur.
Meta verideki search anahtarı, mevcutsa, bir dize veya dizi değerine (diziler dizisi) sahip olmalıdır; bu, üst düzey arama yolunun önüne eklenecek arama yoludur.
module
Meta veriler sabit bir jq ifadesi olmalıdır. homepage gibi anahtarlara sahip bir nesne olmalıdır. Şu anda jq bu meta verileri kullanmaz, ancak modulemeta yerleşik fonksiyonu aracılığıyla kullanıcılara sunulur.
modulemeta Girdi olarak bir modül adı alır ve modülün içe aktarmalarını (meta veriler dahil) deps anahtarı için bir dizi değeri olarak, modülün tanımlı fonksiyonlarını ise defs anahtarı için bir dizi değeri olarak içeren bir nesne halinde modülün meta verilerini çıktı olarak verir.
Programlar bunu bir modülün meta verilerini sorgulamak için kullanabilir ve ardından bunu, örneğin eksik bağımlılıkları aramak, indirmek ve kurmak için kullanabilirler.
Renkler
Alternatif renkleri yapılandırmak için, JQ_COLORS ortam değişkenini bu sırayla "1;31" gibi iki nokta üst üste ile ayrılmış kısmi terminal kaçış dizileri listesine ayarlamanız yeterlidir:
• null için renk
• false için renk
• true için renk
• sayılar için renk
• dizeler (strings) için renk
• diziler (arrays) için renk
• nesneler (objects) için renk
• nesne anahtarları (object keys) için renk
Varsayılan renk şeması, JQ_COLORS="0;90:0;39:0;39:0;39:0;32:1;39:1;39:1;34" ayarıyla aynıdır.
Bu, VT100/ANSI kaçış karakterleri için bir kılavuz değildir. Ancak, bu renk özelliklerinin her biri, noktalı virgülle ayrılmış iki sayıdan oluşmalıdır; burada ilk sayı aşağıdakilerden biridir:
• 1 (parlak)
• 2 (sönük)
• 4 (altı çizili)
• 5 (yanıp sönen)
• 7 (ters)
• 8 (gizli)
ve ikincisi aşağıdakilerden biridir:
• 30 (siyah)
• 31 (kırmızı)
• 32 (yeşil)
• 33 (sarı)
• 34 (mavi)
• 35 (macenta)
• 36 (turkuaz)
• 37 (beyaz)
Hatalar
Muhtemelen vardır. Bunları şu adreste bildirin veya tartışın:
https://github.com/jqlang/jq/issues
Yazar
Stephen Dolan mu@netsoc.tcd.ie
Aralık 2023 JQ(1)