jq One-Liners تصفية وتحويل JSON من السطر الأوسع دون كتابة برنامج
سبع وصفات عملية لـ jq لمهندسي الخلفية والمسؤولين عن البنية التحتية — تشمل select، map، to_entries، del، group_by، وتحويل واجهات برمجة التطبيقات في الواقع. يُعرض المدخل والخرج لكل نمط.
أنت تنظر إلى استجابة واجهة برمجة تطبيقات مُختصرة في موجه الأوامر. تحتاج إلى استخراج 3 حقول، وتصفية القيم المُعدة، وتحويل النتيجة إلى أمر آخر. كتابة سكربت بيثون لهذا يتطلب 20 سطرًا و2 دقائق لا تمتلكها. jq يُعالج ذلك في أمر واحد — إذا كنت تعرف الأنماط.
سبع وصفات أدناه. تغطي كل وصفة نمطًا ستجد استخدامه بشكل متكرر عند العمل مع استجابات واجهة برمجة تطبيقات أو ملفات سجل. تُعرض المدخلات والعمليات والنتائج لكل وصفة.
تثبيت
brew install jq # macOS
apt-get install jq # Ubuntu/Debian
apk add jq # Alpine (Docker images)
الوصفة 1: استخراج حقل من كل عنصر في المصفوفة
الشيء الأكثر شيوعًا الذي ستفعله مع jq: استخراج حقل من كل عنصر في مصفوفة JSON.
المدخل (users.json)
[
{"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"},
{"id": 2, "name": "Bob", "email": "bob@example.com", "role": "user"},
{"id": 3, "name": "Carol", "email": "carol@example.com", "role": "user"}
]
jq '.[].name' users.json
# → "Alice"
# "Bob"
# "Carol" (newline-separated stream)
.[] يمر عبر كل عنصر في المصفوفة؛ .name يُستخرج الحقل. الناتج هو سلسلة — مفيد لتحويلها إلى أوامر أخرى. إذا كنت بحاجة إلى مصفوفة JSON كاملة:
jq 'map(.name)' users.json
# → ["Alice", "Bob", "Carol"]
map(.name) هي اختصار لـ [.[] | .name] — يُطبّق التعبير على كل عنصر ويُغلف النتائج في مصفوفة. ستجد أنك تستخدم map() بشكل متكرر.
الوصفة 2: التصفية باستخدام select
احتفظ فقط بالعناصر التي تتوافق مع شرط معين؛ احذف الباقي.
jq 'map(select(.role == "admin"))' users.json
[
{"id": 1, "name": "Alice", "email": "alice@example.com", "role": "admin"}
]
select(expr) يمر عبر العنصر فقط عندما يكون التعبير صحيحًا — يختفي كل شيء آخر. عند وضعه داخل map() يُحتفظ بالنتيجة كمصفوفة. أمثلة إضافية:
# Numeric comparison
jq 'map(select(.score > 80))' results.json
# Not-null check
jq 'map(select(.error != null))' events.json
# String contains (requires test)
jq 'map(select(.message | test("timeout")))' logs.json
الوصفة 3: إعادة تشكيل الكائنات باستخدام map
اختر فقط الحقول التي تحتاجها وقم بتعديل أسمائها بشكل اختياري في نفس العملية.
jq 'map({name: .name, role: .role})' users.json
[
{"name": "Alice", "role": "admin"},
{"name": "Bob", "role": "user"},
{"name": "Carol", "role": "user"}
]
أنت تُنشئ كائنًا جديدًا لكل عنصر. لتعديل اسم مفتاح، قم بتغيير الجانب الأيسر من العلامة:
jq 'map({username: .name, access_level: .role})' users.json
مختصر يوفر تقليلًا في عدد الأزرار: {name} تُليها {name: .name}. إذا كنت ترغب في الحقل كما هو، لا تحتاج إلى كتابة المفتاح مرتين:
jq 'map({id, name, role})' users.json
الوصفة 4: إعادة تسمية المفاتيح باستخدام to_entries و from_entries
map مثالي عندما تعرف أن المفاتيح موجودة. عندما تحتاج إلى تغيير المفاتيح نفسها — إضافة مقدمة، تغيير نمط التسمية، أو إعادة تسمية بناءً على مرجع — to_entries هي النمط الصحيح.
المدخل (config.json)
{"api_url": "https://api.example.com", "timeout": 30, "retry_count": 3}
# Add cfg_ prefix to every key
jq 'to_entries | map(.key = "cfg_" + .key) | from_entries' config.json
{"cfg_api_url": "https://api.example.com", "cfg_timeout": 30, "cfg_retry_count": 3}
to_entries تُحول {"k": "v"} داخل [{"key": "k", "value": "v"}]. بعد تغيير العناصر في المصفوفة الناتجة، from_entries تُعيد بناء الكائن. لتعديل مفتاح واحد فقط دون تغيير الباقي:
jq 'to_entries | map(if .key == "api_url" then .key = "endpoint" else . end) | from_entries' config.json
الوصفة 5: إزالة الحقول باستخدام del
العكس المعاكس للإعادة التشكيل: احتفظ بكل شيء واحذف بعض الحقول المحددة. الاستخدام الرئيسي هو إزالة البيانات الحساسة قبل تسجيلها أو قبل إرسال محتوى إلى خدمة خارجية.
jq 'map(del(.email))' users.json
[
{"id": 1, "name": "Alice", "role": "admin"},
{"id": 2, "name": "Bob", "role": "user"},
{"id": 3, "name": "Carol", "role": "user"}
]
احذف عدة حقول في نفس الوقت، أو حذف مسارات مُضمنة:
# Multiple top-level fields at once
jq 'del(.password, .token, .refresh_token)' user.json
# Nested path
jq 'del(.user.internal_id)' response.json
# All fields named "debug" at any depth (recursive descent)
jq 'del(.. | .debug? // empty)' response.json
الوصفة 6: التصفية، إعادة التشكيل، والترتيب في نفس العملية
الإيجابية الحقيقية هي تسلسل هذه الوحدات الأساسية. إليك نمطًا يظهر بشكل متكرر عند العمل مع استجابات واجهة برمجة تطبيقات مُقسّمة: الدخول إلى مصفوفة مُضمنة، التصفية، إعادة تشكيل الكائنات، وترتيب النتيجة.
المدخل (repos.json)
{
"total_count": 3,
"items": [
{"id": 1, "name": "repo-alpha", "stargazers_count": 142, "language": "Go", "private": false},
{"id": 2, "name": "repo-beta", "stargazers_count": 89, "language": "Python", "private": true},
{"id": 3, "name": "repo-gamma", "stargazers_count": 310, "language": "Go", "private": false}
]
}
jq '.items
| map(select(.private == false and .language == "Go"))
| sort_by(-.stargazers_count)
| map({name, stars: .stargazers_count})' repos.json
[
{"name": "repo-gamma", "stars": 310},
{"name": "repo-alpha", "stars": 142}
]
السلسلة:
.items— الدخول إلى المصفوفة المضمنةmap(select(...))— التصفية في عملية واحدة؛andتُربط شروطsort_by(-.stargazers_count)— تُعكس القيمة للترتيب المتناقص؛sort_by(.field)بحد ذاتها تُعطي ترتيبًا تصاعديًاmap({name, stars: .stargazers_count})— التشكيل النهائي؛{name}هي اختصار لـ{name: .name}
الوصفة 7: تحليل تكرار مستويات السجلات باستخدام group_by
تحليل التكرار على مخرجات السجلات المبنية — لا حاجة لقاعدة بيانات، ولا حاجة لعمليات awk معقدة.
المدخل (logs.json)
[
{"level": "error", "msg": "connection timeout", "service": "auth"},
{"level": "info", "msg": "request received", "service": "api"},
{"level": "error", "msg": "null pointer exception", "service": "worker"},
{"level": "warn", "msg": "slow query detected", "service": "db"},
{"level": "error", "msg": "rate limit exceeded", "service": "api"}
]
jq 'group_by(.level) | map({level: .[0].level, count: length}) | sort_by(-.count)' logs.json
[
{"level": "error", "count": 3},
{"level": "info", "count": 1},
{"level": "warn", "count": 1}
]
group_by(.level) تُرجع مصفوفة من مصفوفات — كل مصفوفة فرعية تحتوي على جميع العناصر التي تمتلك نفس قيمة المستوى. .[0].level تُأخذ اسم المستوى من العنصر الأول في المجموعة؛ length تُعدّ عدد العناصر في المجموعة.
أضف تحليلًا حسب الخدمة في نفس الاستعلام:
jq 'group_by(.level) | map({
level: .[0].level,
count: length,
services: map(.service) | unique
})' logs.json
الرجوع السريع
الأنماط المذكورة أعلاه على شكل جدول عند الحاجة إلى تذكير سريع:
| ما تريده | تعبير jq |
|---|---|
| جميع القيم الخاصة بالحقل | map(.field) |
| تصفية العناصر المطابقة | map(select(.field == "val")) |
| إعادة تشكيل كل كائن | map({newKey: .oldKey}) |
| إعادة تسمية جميع المفاتيح | to_entries | map(.key = ...) | from_entries |
| إزالة الحقول | map(del(.field1, .field2)) |
| ترتيب تصاعدي | sort_by(.field) |
| ترتيب متناقص | sort_by(-.field) |
| حساب التكرار حسب المجموعة | group_by(.field) | map({key: .[0].field, count: length}) |
| استرجاع جميع المفاتيح من الكائن | keys |
| حساب العناصر في المصفوفة | length |
| القيم المميزة الخاصة بالحقل | map(.field) | unique |
قبل البدء: تهدئة الكتلة
تُرجع الاستجابات من واجهة برمجة تطبيقات غالبًا بشكل مختصر أو مُضمن بشكل عميق. إذا لم تكن متأكدًا من المسار الذي تحتاجه، قم بوضع JSON داخل تنسيق JSON — يُظهر التصحيح بعناصر قابلة للانكماش بحيث يمكنك رؤية المسار قبل كتابة التعبير jq بعد تنفيذ تغيير، يكون الأداة مفيدة لتأكيد الفرق قبل وبعد عند إعادة التشكيل أو إزالة الحقول، وتحقيق تأكيد على عدم حدوث تغيير غير متوقع. مقارنة جيسون تغطي هذه السبعة أنماط معظم عمليات التعديل على JSON التي ستجد استخدامها في السطر الأوامر. القوة الحقيقية تكمن في تسلسلها — بمجرد أن تتمكن من التصفية، إعادة التشكيل، والترتيب، يمكنك معالجة معظم استجابات واجهة برمجة تطبيقات دون الحاجة إلى ملف سكربت.
jq One-Liners: التصفية والتحويل من JSON من خلال السطر الأوامر دون كتابة سكربت 2
قد يعجبك أيضاً
تثبيت ملحقاتنا
أضف أدوات IO إلى متصفحك المفضل للوصول الفوري والبحث بشكل أسرع
恵 وصلت لوحة النتائج!
لوحة النتائج هي طريقة ممتعة لتتبع ألعابك، يتم تخزين جميع البيانات في متصفحك. المزيد من الميزات قريبا!
