jq با عبور دادن دادهی ورودی JSON از یک عبارت واحد (که بهشکل خط لولهای از فیلترها نوشته میشود) کار میکند تا به دادهی تبدیلشدهی موردنظر برسد.
jq
زبان jq بهوسیلهی برنامهی jq پیادهسازی شده است.
این برنامه چندین گزینهی کاربردی خط فرمان در اختیار میگذارد که نحوهی مصرف ورودی و نحوهی ارائهی خروجی را کنترل میکنند.
در مثالهای زیر با اینها روبهرو میشوید:
-n یا --null-input
معمولاً به برنامهی jq یک فایل برای خواندن داده میشود، یا شما داده را به ورودیاش میفرستید.
گزینهی --null-input به شما اجازه میدهد بدون هیچ ورودیای دادهی JSON تولید کنید.
-c یا --compact-output
jq بهطور پیشفرض خروجیاش را مرتب و خوانا چاپ میکند.
وقتی داده مرتب قالببندی شده باشد، دیدنش برای انسانها بسیار مفید است.
اما برای ماشینها این کار لازم نیست: گزینهی --compact-output فاصلههای قالببندی را حذف میکند تا اندازهی JSON حاصل کمینه شود.
-f filename یا --from-file filename
برنامهی jq را از filename بخوانید، بهجای اینکه آن را روی خط فرمان بنویسید.
هم sed و هم awk برای همین منظور از گزینهی -f استفاده میکنند.
این را در اسکریپتهای تست تمرینهای عملی خواهید دید.
برای جزئیات همهی گزینهها، راهنما را ببینید.
فیلترها با نام عبارتها هم شناخته میشوند.
یک فیلتر ورودی میگیرد و خروجی تولید میکند.
مثل همان روشی که در یک پوستهی یونیکس کار میکنید، میتوانید فیلترها را با لولهی | به هم بپیوندید تا خروجی یک فیلتر به ورودی فیلتر دیگر وصل شود.
.
این سادهترین فیلتر است.
ورودیاش را همانطور که هست به خروجی میفرستد.
برای نمونه، jq بهطور پیشفرض خروجی را مرتب چاپ میکند، پس اگر JSON را به فیلتر . بدهید، خروجی مرتب و قالببندیشده را مجانی بهدست میآورید!
$ echo '[1, 2, 3]' | jq '.'
[
1,
2,
3
]
این آشنایی سریعی است با کار کردن با آرایهها. بعداً این موضوع را با جزئیات بیشتری بررسی خواهیم کرد.
به عناصر آرایه با کروشه دسترسی پیدا میکنید و اندیسگذاری از صفر شروع میشود.
$ echo '[10, 20, 30]' | jq '.[1]'
20
یک فیلتر میتواند با قرار دادن یک عبارت میان [ و ] یک آرایه بسازد
با فهرستی معلوم از عناصر:
jq -n '[1, 2, 3]'
برای گرد آوردن جریانی از عناصر: برای نمونه،
range تابعی است که جریانی از اعداد تولید میکند
$ jq -n 'range(10; 70; 15)'
10
25
40
55
استفاده از [] نتایج عبارت را در یک آرایه گرد میآورد
$ jq -c -n '[range(10; 70; 15)]'
[10,25,40,55]
کاما فقط نحوی نیست که عناصر آرایه را از هم جدا میکند. کاما یک عملگر است که جریانها را به هم میپیوندد.
برای نمونه [1, 2, 3] یک فیلتر است که با سازندهی آرایه یعنی []، نتیجهی بههمپیوستن سه عبارت 1، 2 و 3 را گرد میآورد.
آیا نقطهویرگولهای range(10; 70; 15) را در بالا دیدید؟
چون کاماها در زبان jq کاربرد مشخصی دارند، توابعی که چند آرگومان میگیرند، آرگومانها را با نقطهویرگول از هم جدا میکنند.
آشنایی سریع با شیءها.
مانند بسیاری از زبانهای برنامهنویسی، برای دسترسی به ویژگیهای شیء از نقطه استفاده کنید
$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
از کروشهها هم میتوان برای شیءها استفاده کرد، اما در آن صورت برای رشتههای ثابت به گیومه نیاز دارید. این یکی از روشهای کار با کلیدهایی است که فاصله دارند.
$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"
میتوانید با {} و جفتهای key: value یک شیء بسازید.
دور کلیدهایی که رشتههای «ساده» هستند به گیومه نیازی نیست.
jq -n '{question: (6 * 9), answer: 42}'
خروجی این است
{
"question": 54,
"answer": 42
}
برای اینکه با کلید مانند یک عبارت رفتار شود، باید آن را داخل پرانتز بگذارید (مورد زیر هم همان خروجی بالا را میدهد).
echo '[["question", "answer"], [54, 42]]' \
| jq '{(.[0][0]): .[1][0], (.[0][1]): .[1][1]}'
خیلی رایج است که بخواهید زیرمجموعهای از کلیدها را از یک شیء بزرگ بیرون بکشید.
برای نمونه، برای بیرون کشیدن id و name از
{
"id": 101,
"name": "alpha widget",
"specifications": {...}
}
میتوانستیم این را بنویسیم
{id: .id, name: .name}
اما چون این کار خیلی رایج است، یک نحو مختصر برایش وجود دارد:
{id, name}
برای نمونه، فرض کنید file.json این را در خود دارد
{
"key1": "value1",
"key2": [5, 15, 25]
}
بیایید طول آرایهی key2 را حساب کنیم:
$ jq '.key2 | length' file.json
3
اینجا خروجی عبارت .key2 را بهعنوان ورودی به length لوله میکنیم، که همانطور که انتظار میرود تعداد عناصر آرایه را خروجی میدهد.
این یکی از جنبههای jq است که کمی باید به آن عادت کرد:
بیشتر توابع (اما نه همهشان) مثل فیلتر عمل میکنند؛ یعنی داده را به ورودی فیلتر میدهید، نه بهعنوان آرگومان.
در این مثال، دادهی JSON ورودی نادیده گرفته میشود و هیچ تأثیری بر خروجی ندارد:
$ echo '{"answer": 42}' | jq '6 * 9'
54
یک فیلتر میتواند بیش از یک مقدار خروجی بدهد.
برای نمونه، فیلتر .[] هر عنصر یک آرایه را بهصورت مقداری جداگانه خروجی میدهد:
$ jq -n -c '[1, 2, 3]'
[1,2,3]
$ jq -n -c '[1, 2, 3] | .[]'
1
2
3
اگر چنین فیلتری را به فیلتر دیگری لوله کنید، فیلتر دوم برای هر مقدار اجرا میشود:
$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6
این شبیه پیمایش ضمنی است.
وقتی این تکنیک را بفهمید، میبینید که فیلترهای بسیار قدرتمند jq میتوانند خیلی مختصر باشند.
از پرانتز برای گروهبندی زیرعبارتها و تعیین ترتیب عملیات استفاده میشود، درست مانند زبانهای دیگر.
در jq، ممکن است نیاز به آنها تا حدودی غیرمنتظره به نظر برسد.
برای نمونه، فرض کنید میخواهیم آرایهای با ۲ عنصر بسازیم: جذر ۹؛ و e به توان ۱.
دو عبارت جداگانه اینها هستند: 9 | sqrt و 1 | exp.
انتظار داریم خروجی آرایهی [3, 2.7...] باشد.
$ jq -n '[ 9|sqrt, 1|exp ]'
[
20.085536923187668,
2.718281828459045
]
چرا چیزی را که انتظار داشتیم بهدست نیاوردیم؟ jq آن را اینطور تفسیر میکند:
[ ((9|sqrt), 1) | exp ]
jq جریانی از دو عنصر (3 و 1) میسازد که هر کدام به exp داده میشوند.
باید مطمئن شویم که exp فقط یک عدد را بهعنوان ورودی میگیرد.
به بیان دیگر، باید تضمین کنیم که لوله پیش از کاما ارزیابی میشود.
$ jq -n '[ 9|sqrt, (1|exp) ]'
[
3,
2.718281828459045
]
از راهنما
jq از همان مجموعهی انواع داده پشتیبانی میکند که JSON پشتیبانی میکند: اعداد، رشتهها، مقادیر منطقی، آرایهها، شیءها (که در زبان JSON همان هشهایی با کلیدهای صرفاً رشتهای هستند) و «null».
در تمرینهای بعدی دربارهی اینها بیشتر یاد خواهید گرفت.
فضای سفید در jq معنادار نیست.
از فاصله، تب و خط جدید هرطور که مناسب میدانید برای قالببندی کدتان استفاده کنید.
ما از هیچ راهنمای سبکی که برای jq وجود داشته باشد آگاه نیستیم.
مقدارها در jq تغییرناپذیر هستند.
فیلترهایی که یک مقدار را تغییر میدهند، مقدار جدیدی تولید میکنند.
این یعنی jq متغیر سراسری ندارد؛ باید عادت کنید که حالت را از یک فیلتر به فیلتر دیگر بفرستید.
مقدارهای false و null بهعنوان «غلط» در نظر گرفته میشوند. هر مقدار دیگری
(از جمله عدد صفر و رشته/آرایه/شیء خالی) «درست» است.
بدون اینکه خیلی عمیق شویم (توابع موضوع تمرینی دیگر خواهند بود)، در ادامه چند تابع درونی مفید را میبینید:
با گرفتن یک آرایه بهعنوان ورودی، تعداد عناصر آرایه را خروجی میدهد.
$ jq -n '[10, 20, 30, 40] | length'
4
این عملگر بسته به نوع عملوندهایش کارهای متفاوتی انجام میدهد: اعداد را جمع میکند، رشتهها را به هم میچسباند، آرایهها را به هم میپیوندد، و شیءها را ادغام میکند.
$ jq -c -n '
3 + 4,
"foo" + "bar",
["a", "b"] + ["c"],
{"m": 10} + {"n": 20}
'
7
"foobar"
["a","b","c"]
{"m":10,"n":20}
add تابعی است که یک آرایه میگیرد و موردی را برمیگرداند که همهی عناصرش با قواعد + به هم جمع شدهاند.
[1, 2, 3] | add خروجی 6 را میدهد.
با گرفتن یک آرایه بهعنوان ورودی و یک فیلتر بهعنوان آرگومان، آرایهای را خروجی میدهد که فیلتر روی هر عنصرش اعمال شده است
$ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
[2,4,6,8]
با گرفتن مقداری ورودی و یک فیلتر بهعنوان آرگومان:
null، بلکه واقعاً هیچ خروجیای)برای نمونه، با گرفتن چند عدد، آنهایی که بر ۳ بخشپذیرند را انتخاب کنید
$ jq -n 'range(10) | select(. % 3 == 0)'
0
3
6
9
به یاد بیاورید که range یک جریان از اعداد خروجی میدهد.
select برای هر عدد یک بار فراخوانی میشود.
فقط اعدادی که از عبارت «عبور میکنند» خروجی داده میشوند.
اغلب لازم است عناصری از یک آرایه را انتخاب کنید. برای این کار چند روش وجود دارد.
با ورودی ["Anne", "Bob", "Cathy", "Dave"]، نامهایی با طول ۴ را انتخاب کنید.
از map و select با هم استفاده کنید
map(select(length == 4))
آرایه را به عناصر جدا از هم بشکنید، روی آن جریان select بزنید و نتایج را گرد آورید
[ .[] | select(length == 4) ]
توضیحها با کاراکتر # شروع میشوند و تا پایان خط ادامه دارند.