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"
অবজেক্টের জন্যও বন্ধনী ব্যবহার করা যায়, তবে তখন স্ট্রিং লিটারেলের জন্য কোটেশন প্রয়োজন। স্পেস আছে এমন কী (key) নিয়ে কাজ করার এটি একটি পদ্ধতি।
$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"
{} এবং key: value জোড়া দিয়ে আপনি একটি অবজেক্ট তৈরি করতে পারেন।
"সরল" স্ট্রিং যেসব কী (key), সেগুলোর চারপাশে কোটেশন প্রয়োজন হয় না।
jq -n '{question: (6 * 9), answer: 42}'
আউটপুট দেয়
{
"question": 54,
"answer": 42
}
কী (key)-কে একটি এক্সপ্রেশন হিসেবে ধরতে হলে এটিকে প্রথম বন্ধনীর ভেতরে রাখতে হবে (নিচেরটিও উপরের মতোই আউটপুট দেয়)।
echo '[["question", "answer"], [54, 42]]' \
| jq '{(.[0][0]): .[1][0], (.[0][1]): .[1][1]}'
বড় একটি অবজেক্ট থেকে কী (key)-এর একটি উপসেট বের করা বেশ সাধারণ ব্যাপার।
উদাহরণস্বরূপ, নিচের জিনিস থেকে 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-এর ভাষায় কেবল স্ট্রিং কী (key) বিশিষ্ট হ্যাশ), এবং "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) ]
কমেন্ট শুরু হয় # অক্ষর দিয়ে এবং লাইনের শেষ পর্যন্ত চলতে থাকে।