42-minishell — صدفة شبيهة بـ Bash مكتوبة بلغة C
صدفة مصغّرة شبيهة بـ Bash مكتوبة بلغة C، تبني سلسلة كاملة من التقطيع إلى التنفيذ: توسيع المتغيّرات، الأنابيب، إعادة التوجيه، الإشارات، وسبعة أوامر داخلية.

عن هذا المشروع
صدفة مصغّرة شبيهة بـ Bash مكتوبة بلغة C: محلّل نصّي، توسيع للمتغيّرات، أنابيب وإعادة توجيه، معالجة للإشارات، وسبعة أوامر داخلية مبنية من الصفر.
التقنيات
مشروع ضمن مسار 42 أبوظبي — إعادة بناء صدفة شبيهة بـ Bash بلغة C اعتماداً على استدعاءات النظام وحدها.
نظرة عامة
minishell صدفة تفاعلية مكتوبة بلغة C، تقرأ سطر الأوامر من المستخدم وتحوّله إلى عمليات حقيقية على النظام. الهدف ليس تقليد Bash بالكامل، بل إعادة بناء الجزء الجوهري منه: كيف يتحوّل نصّ مكتوب إلى fork وexecve وأنابيب وملفات مُعاد توجيهها.
الصدفة تدعم سبعة أوامر داخلية منفّذة يدوياً:
| الأمر | الوظيفة |
|---|---|
echo |
طباعة النصوص، مع دعم الخيار -n لحذف سطر النهاية |
cd |
تغيير مجلد العمل بمسار نسبي أو مطلق |
pwd |
طباعة مجلد العمل الحالي |
export |
تصدير متغيّرات الصدفة إلى البيئة |
unset |
حذف متغيّر من البيئة |
env |
عرض البيئة الحالية |
exit |
إنهاء الصدفة بحالة خروج محدّدة |
المشكلة
الصدفة تبدو بسيطة من الخارج ـ سطر نصّي يُنفَّذ ـ لكنها تخفي ثلاث مشكلات متشابكة:
- النصّ ليس كلمات. الاقتباسات المفردة والمزدوجة تغيّر معنى المسافات وعلامة
$، فلا يكفي تقسيم السطر على الفراغات. - حالة تعيش بين الأوامر. متغيّرات البيئة، مجلد العمل، وحالة الخروج الأخيرة يجب أن تبقى صحيحة عبر آلاف الأوامر المتتالية.
- الإشارات لها معنى مزدوج.
Ctrl-Cيجب أن يقاطع الأمر الجاري لا الصدفة نفسها، والسلوك يختلف بين الوضع التفاعلي ووضع تنفيذ عملية ابن.
التخطيط
قُسِّم العمل إلى مراحل متسلسلة، كل مرحلة قابلة للاختبار قبل الانتقال إلى ما بعدها:
| المرحلة | ما تُنجزه |
|---|---|
| الموجّه (Prompt) | حلقة القراءة التفاعلية وسجلّ الأوامر |
| جدول التجزئة | تخزين متغيّرات البيئة والوصول إليها بزمن ثابت |
| المقطِّع (Tokenizer) | تحويل السطر إلى رموز مع احترام الاقتباسات |
| توسيع المتغيّرات | استبدال $VAR و$? بقيمها |
| الأوامر الداخلية | تنفيذ السبعة داخل عملية الصدفة نفسها |
| التحليل والتنفيذ | بناء شجرة الأمر ثم تشغيلها عبر fork/execve |
| الإشارات | ضبط سلوك SIGINT وSIGQUIT في كل وضع |
| Norme وصيد العلل | الالتزام بمعيار كتابة 42 ثم اختبار الحالات الحدّية |
ترتيب المراحل ليس اعتباطياً: جدول التجزئة سبق المقطِّع لأن التوسيع لا يمكن اختباره دون مصدر موثوق للمتغيّرات.
القرارات المعمارية
جدول تجزئة للبيئة بدل مصفوفة char** envp. التمثيل الأصلي للبيئة مصفوفة نصوص بصيغة KEY=VALUE، والبحث فيها خطّي وكل تعديل يعني إعادة بناء المصفوفة كاملة. جدول التجزئة يجعلexportوunset و$VAR عمليات مباشرة، ولا تُعاد المصفوفة إلا لحظة تسليمها إلى execve.
فصل التقطيع عن التحليل. المقطِّع لا يعرف شيئاً عن الأنابيب أو إعادة التوجيه؛ مهمّته الوحيدة إنتاج رموز صحيحة رغم الاقتباسات. دمج المرحلتين ـ وهو الخيار الأسرع للكتابة ـ كان سيجعل كل خطأ في الاقتباس يظهر كخطأ في التنفيذ، وهو أصعب أنواع العلل تتبّعاً.
تنفيذ الأوامر الداخلية داخل العملية الأصلية. لو نُفِّذ cd أو export داخل عملية ابن لضاع أثرهما فور انتهائها. لذلك تُنفَّذ الأوامر الداخلية في عملية الصدفة نفسها ما لم تكن جزءاً من أنبوب، حيث لا معنى لبقاء أثرها أصلاً.
التنفيذ
دورة حياة السطر الواحد تمرّ بالخطوات ذاتها في كل مرة: قراءة، تقطيع، توسيع، تحليل، تنفيذ، ثم تحديث حالة الخروج.
- الأنابيب — سلسلة
cmd1 | cmd2 | cmd3تُنشئ أزواجpipe()وتربط مخرج كل عملية بمدخل التالية، مع إغلاق دقيق للواصفات غير المستخدمة في كل ابن ـ وهو المصدر الأول لتعليق الصدفة عند الإهمال. - إعادة التوجيه —
<و>و>>و<<(heredoc)، مُطبَّقة عبرdup2بعدforkوقبلexecve. - التوسيع —
$VARمن جدول البيئة، و$?من حالة خروج آخر أمر، مع تعطيل التوسيع كاملاً داخل الاقتباس المفرد. - الإشارات — في الوضع التفاعلي يعيد
SIGINTرسم الموجّه على سطر جديد دون إنهاء الصدفة؛ وأثناء تنفيذ أمر خارجي يُترك للابن ليموت به، وتُترجم حالته إلى الرقم المتوقّع. - البحث عن التنفيذيات — تفكيك
PATHوتجريب كل مسار قبل إعلانcommand not found.
النتيجة والدروس
الصدفة تشغّل أوامر مركّبة تجمع الأنابيب وإعادة التوجيه والتوسيع في سطر واحد، وتتصرّف كما يتوقّع مستخدم Bash في الحالات الشائعة.
- إدارة واصفات الملفات هي المشروع الحقيقي. معظم حالات التعليق لم تكن أخطاء منطق بل واصفاً مفتوحاً نُسي إغلاقه في أحد الأبناء.
- الاقتباسات تُحسم في التقطيع لا في التنفيذ. كل محاولة لمعالجتها متأخراً أنتجت حالات خاصة تتكاثر بلا نهاية.
- القراءة من المعيار توفّر وقتاً. وصف Shell Command Language في POSIX أجاب عن أسئلة سلوكية كثيرة كان تخمينها سيستهلك أياماً.
الروابط
- المستودع: github.com/i99dev/42-minishell