تعمل 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 للغرض نفسه.
سترى هذا مستخدمًا في نصوص الاختبار الخاصة بالتمارين التدريبية.
راجع الدليل للحصول على تفاصيل حول جميع الخيارات.
المرشِّحات تُعرف أيضًا باسم التعبيرات.
المرشِّح يأخذ مدخلًا وينتج مخرجًا.
وكما تعمل في صدفة Unix، يمكنك ربط المرشِّحات بأنبوب | لتوصيل مخرجات أحدها بمدخلات آخر.
.
هذا أبسط مرشِّح.
إنه يمرّر مدخلاته إلى مخرجاته ببساطة.
على سبيل المثال، يطبع 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، قد تبدو الحاجة إليها مفاجئة بعض الشيء.
على سبيل المثال، لنفترض أننا نريد بناء مصفوفة بعنصرين: الجذر التربيعي لـ 9؛ و_e_ مرفوعًا إلى القوة 1.
التعبيران المنفردان هما 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، بل لا مخرجات على الإطلاق)على سبيل المثال، عند إعطاء بعض الأعداد، اختر تلك القابلة للقسمة على 3
$ jq -n 'range(10) | select(. % 3 == 0)'
0
3
6
9
تذكّر أن range تُخرج تدفّقًا من الأعداد.
سيُستدعى select مرة واحدة لكل عدد.
ولا تُخرج إلا الأعداد "المجتازة" للتعبير.
غالبًا ما تحتاج إلى اختيار عناصر من مصفوفة. وهناك أسلوبان لذلك.
مع المدخل ["Anne", "Bob", "Cathy", "Dave"]، اختر الأسماء التي طولها 4.
استخدم map وselect معًا
map(select(length == 4))
فكّك المصفوفة إلى عناصر، وطبّق select على ذلك التدفّق، واجمع النتائج
[ .[] | select(length == 4) ]
تبدأ التعليقات بمحرف # وتستمر حتى نهاية السطر.