محلّل تعابير Cron

اقرأ تعبير cron بلغة واضحة، واعرف بالضبط موعد تشغيله القادم.

الدقيقة · الساعة · اليوم من الشهر · الشهر · اليوم من الأسبوع. وتعمل الاختصارات مثل ‎@daily أيضًا.

جرّب:

يعمل هذا

عند 03:00، أيام الاثنين

التشغيلات الست القادمة · UTC

  1. 2026-09-21 03:00الاثنين
  2. 2026-09-28 03:00الاثنين
  3. 2026-10-05 03:00الاثنين
  4. 2026-10-12 03:00الاثنين
  5. 2026-10-19 03:00الاثنين
  6. 2026-10-26 03:00الاثنين

معروض بتوقيت UTC. أما جدول cron الحقيقي فيعمل بتوقيت الخادم، وهناك بالضبط يسبّب التوقيت الصيفي المتاعب — انظر أدناه.

حقلًا حقلًا

الدقيقة
00
الساعة
33
اليوم من الشهر
*أي قيمة
الشهر
*أي قيمة
اليوم من الأسبوع
11

ما يجدر معرفته عن هذا الجدول

  • اليوم 31 غير موجود في كل شهر، فلن تعمل المهمة في تلك الأشهر ببساطة.
  • ‏29 فبراير لا يوجد إلا في السنوات الكبيسة — أي أن هذا يعمل مرة كل أربع سنوات.

خمسة حقول، أخشنها في الآخر

الموضعالحقلالمدىملاحظات
1الدقيقة0–59
2الساعة0–23بنظام 24 ساعة، بتوقيت الخادم
3يوم الشهر1–31الأيام غير الموجودة تُتخطّى ببساطة
4الشهر1–12أو JANDEC
5يوم الأسبوع0–7‏0 و7 كلاهما يعني الأحد. أو SUNSAT

وداخل الحقل: * تعني أياً كان، و, تعدّد القيم، و- تعطي مدى، و/ تخطو. فـ */15 في حقل الدقائق تعني كل خمس عشرة دقيقة؛ و5/10 تعني من 5 فصاعداً بمقدار عشرة، أي 5 و15 و25 وهكذا. وقد تلتف المديات، فـ FRI-MON طريقة صالحة لقول عطلة نهاية الأسبوع مع طرفيها.

القاعدة التي توقع الجميع

هذا هو الشيء الوحيد الجدير بأن تخرج به من هذه الصفحة.

حين يكون الحقلان — يوم الشهر ويوم الأسبوع — مقيَّدين معاً، يشغّل cron المهمة حين يطابق أيٌّ منهما. لا كلاهما. إنها «أو»، وتُقرأ كأنها «و».

0 0 1 * MON   # NOT "the 1st, if it is a Monday"
              # Actually: every 1st, AND every Monday

ذلك الجدول ينطلق نحو خمس مرات شهرياً. الصقه في المحلّل أعلاه وانظر إلى مواعيد التشغيل التالية — التسلسل يفضح الأمر فوراً.

ولا تنطبق القاعدة إلا حين يكون الحقلان مقيَّدين. فإن كان أحدهما * حكم الآخر وحده، ولهذا يتصرف 0 0 * * MON تماماً كما هو متوقَّع. والسلوك منصوص عليه في مواصفة POSIX وينفّذه كل cron شائع، فليست علّة يمكن ضبط الإعدادات للتخلص منها.

ولاشتراط الأمرين معاً فعلاً، قيّد حقلاً واحداً في الجدول وافحص الآخر في مطلع المهمة:

0 0 * * MON  [ "$(date +\%d)" = "01" ] && /usr/local/bin/job

التوقيت الصيفي، الذي يكسر المهام مرتين كل عام

يعمل cron بالمنطقة الزمنية المحلية للخادم ما لم يُقَل غير ذلك، والوقت المحلي ليس متصلاً. فحين تُقدَّم الساعات تختفي ساعة: قد تُتخطّى مهمة مجدولة للساعة 02:30 كلياً أو تنطلق في 03:30، تبعاً لنسخة cron التي لديك. وحين تُؤخَّر تقع الساعة 01:30 مرتين، وقد تقع معها المهمة مرتين.

ويبذل Vixie cron الحديث جهداً — إذ تُشغَّل المهام الفائتة بسبب القفزة إلى الأمام مرة واحدة بعدها عادةً — لكن السلوك ليس متسقاً بين التطبيقات، ومجدولات الحاويات تختلف مرة أخرى.

والحل المتين تشغيل المجدوِل بتوقيت UTC والتحويل عند الأطراف. ومهام CronJob في كوبرنيتيس تعمل بـ UTC افتراضياً لهذا السبب بالضبط. فإن وجب أن تعمل مهمة في توقيت محلي بعينه، فاقبل أنها ستزيغ ساعةً في جزء من السنة، أو استعمل مجدوِلاً يفهم المناطق الزمنية فهماً صحيحاً — ومؤقتات systemd تفهمها.

أسباب أخرى لعدم تشغيل مهمة cron

  • البيئة شبه فارغة. فـ cron لا يقرأ ملف تعريف الصدفة لديك، فيكون PATH ضئيلاً وبيئتك الافتراضية غير مفعّلة. استعمل المسارات المطلقة دائماً.
  • علامة نسبة مئوية مجرّدة. ففي crontab تعني % سطراً جديداً. فـ date +%Y تنكسر في صمت؛ ويجب أن تُكتب date +\%Y.
  • غياب سطر جديد في النهاية. فبعض نسخ cron تتجاهل السطر الأخير من crontab إن لم ينتهِ بسطر جديد.
  • المخرجات تذهب إلى العدم. فـ cron يرسل المخرجات بريدياً إلى المستخدم، وإن لم يكن البريد مضبوطاً اختفت. فوجّهها إلى ملف سجل كي تكون الإخفاقات مرئية.
  • تشغيلات متداخلة. فـ cron لا ينتظر انتهاء التشغيل السابق. ومهمة تستغرق خمس دقائق على جدول من دقيقة واحدة تتراكم حتى ينهار شيء ما. استعمل flock.

ما لا يستطيع cron التعبير عنه

الحقول مستقلة، فكل ما لا يقسم الساعة أو اليوم قسمةً صحيحة خارج المتناول. فـ «كل تسعين دقيقة» لا يمكن كتابتها. ولا «آخر جمعة في الشهر» في cron القياسي — ولهذا وُجدت L و# في Quartz، ولهذا أيضاً ليستا قابلتين للنقل.

وإن وجدت نفسك تصارع الصياغة، فتلك عادةً إشارة إلى الانتقال إلى مجدوِل يفكّر بالفواصل الزمنية لا بحقول التقويم. فمؤقّت systemd مع OnUnitActiveSec=90min يقول ما قصدته في سطر واحد.

ذات صلة

مواعيد التشغيل أعلاه بتوقيت UTC — ومحوّل الطوابع الزمنية سيضع أياً منها في منطقتك الزمنية، أو في أي صيغة يسجّل بها مجدوِلك. أما لمطابقة النصوص لا للجدولة، فإن مختبِر التعابير النمطية في الجوار.

أسئلة حول cron

لماذا تعمل مهمتي في أيام لم أجدولها؟

شبه المؤكد أنها قاعدة يوم الشهر مع يوم الأسبوع. فحين يكون الحقلان مقيَّدين معاً، يشغّل cron المهمة حين يطابق أيٌّ منهما — لا كلاهما. لذا فإن ‎0 0 1 * MON تنطلق في أول كل شهر وفي كل اثنين، أي نحو خمس مرات شهرياً بدل المرة الواحدة التي قصدتها. وإن كان أحد الحقلين ‎*، فالقاعدة لا تنطبق ويحكم الحقل الآخر وحده. ولاشتراط الأمرين معاً، قيّد حقلاً واحداً في cron وافحص الآخر داخل المهمة نفسها.

ماذا تعني الحقول الخمسة؟

الدقيقة (0–59)، والساعة (0–23)، ويوم الشهر (1–31)، والشهر (1–12)، ويوم الأسبوع (0–7، حيث يعني كلٌّ من 0 و7 يوم الأحد). والقراءة من اليسار إلى اليمين تزداد خشونةً تدريجياً، وهي حيلة مفيدة للحفظ. وبعض المجدولات — Quartz وSpring وعدد من مشغّلات المهام — تضيف حقلاً سادساً للثواني في المقدمة؛ أما crontab القياسي فلا حقل ثوانٍ فيه أصلاً.

ماذا يحدث لمهمة cron عند التوقيت الصيفي؟

يعتمد على التنفيذ، وهنا بالذات تنكسر المهام المجدولة في صمت مرتين كل عام. فحين تُقدَّم الساعات تختفي ساعة كاملة — فقد تُتخطّى مهمة الساعة 02:30 كلياً، أو تعمل في 03:30، تبعاً لنسخة cron. وحين تُؤخَّر تقع الساعة 01:30 مرتين، فقد تعمل المهمة مرتين. أما Vixie cron الحديث ومؤقتات systemd فتحاول التصرف بحكمة، والقديمة لا تفعل. والجواب المتين هو تشغيل العمل المجدول بتوقيت UTC والتحويل عند الأطراف.

ما هي L وW و# ولمَ تُرفض هنا؟

هي امتدادات Quartz — فـ L تعني «الأخير» (آخر يوم في الشهر، آخر جمعة)، وW تعني أقرب يوم عمل، و# تعني «اليوم النوني من الأسبوع في الشهر». وهي مفيدة فعلاً وليست من cron القياسي. فـ crontab ومهام CronJob في كوبرنيتيس وGitHub Actions ترفضها جميعاً أو تسيء قراءتها. وهذا المحلّل يرفض بدل أن يخمّن، لأن جدولاً يتجاهل L في صمت سيكون خاطئاً بالضبط على النحو الذي لا يفحصه أحد.

ماذا يفعل ‎@reboot؟

يشغّل المهمة مرة واحدة عند بدء cron، وعادةً عند إقلاع الجهاز. وليس له جدول متكرر، فلا مواعيد تشغيل تالية تُحسب — ولهذا تقول لك هذه الأداة ذلك بدل أن تعرض قائمة فارغة. ومن الجدير معرفته أن ‎@reboot ينطلق عند بدء عفريت cron لا عند اكتمال إقلاع الجهاز، فكل ما يعتمد على جاهزية الشبكة عليه أن ينتظرها بنفسه.

كيف أشغّل شيئاً كل تسعين دقيقة؟

لا يمكنك التعبير عن ذلك مباشرةً، وهذا قيد حقيقي لا حيلة لم تتعلمها بعد. فحقول cron مستقلة، لذا فإن ‎*/90 في حقل الدقائق غير صالح، ولا سبيل إلى صياغة جدول لا يقسم الساعة أو اليوم قسمةً صحيحة. والمخارج هي مدخلان يغطيان النمط على مدى اليوم، أو — وهو الأصدق — مجدوِل يفكّر بالفواصل الزمنية لا بحقول التقويم، مثل مؤقّت systemd مع OnUnitActiveSec.

آخر مراجعة . وجدت شيئاً لم يعد محدَّثاً؟ أخبِرنا.