شيبانغ (يونكس)

شيبانغ () هو مصطلح يُطلق في أنظمة التشغيل شبيه يونكس على زوج المحارف الموجود في بداية ملف نصي: #!.

عندما يتم استخدام ملف نصي يحتوي على "شيبانغ" كما لو كان ملفاً تنفيذياً، تقوم آلية محمّل البرامج بتحليل بقية السطر الأول من الملف باعتباره توجيهاً للمفسر (Interpreter directive). يقوم المحمّل بتنفيذ برنامج المفسر المحدد، ويمرر إليه المسار الذي استُخدم في البداية لمحاولة تشغيل النص البرمجي (السكربت) كمعامل (Argument)، بحيث يمكن للبرنامج استخدام الملف كبيانات إدخال.

على سبيل المثال، إذا كان هناك نص برمجي مسمى بالمسار path/to/script، ويبدأ بالسطر #! /bin/sh، فإن محمّل البرامج يتلقى تعليمات بتشغيل البرنامج /bin/sh، وتمرير path/to/script كأول معامل له.

عادةً ما يتجاهل المفسر سطر الشيبانغ، لأن الرمز "#" يُعد علامة تعليق في العديد من لغات البرمجة النصية؛ كما أن بعض مفسرات اللغات التي لا تستخدم علامة المربع لبدء التعليقات قد تظل تتجاهل سطر الشيبانغ تقديراً لغرضه.

 الصياغة 
تكون صيغة توجيه مفسر الشيبانغ على النحو التالي:
  #! interpreter [optional-one-arg-only]

حيث أن interpreter هو مسار لبرنامج تنفيذي. المسافة بين  واسم المفسر اختيارية. يمكن أن يكون هناك أي عدد من المسافات أو علامات الجدولة سواء قبل أو بعد اسم المفسر. المعامل الاختياري (optional-arg) يشمل أي مسافات إضافية حتى نهاية السطر.

في لينكس، الملف المحدد بواسطة interpreter يمكن تنفيذه إذا كان يمتلك حقوق التنفيذ وكان واحداً مما يلي:
 ملف تنفيذي أصلي، مثل ثنائيات ELF.
 أي نوع من الملفات التي تم تسجيل مفسر لها عبر آلية binfmt misc (مثل تنفيذ ثنائيات مايكروسوفت .exe باستخدام واين).
 نص برمجي آخر يبدأ بشيبانغ.

في لينكس ومينكس، يمكن أن يكون المفسر نصاً برمجياً أيضاً. تؤدي سلسلة من الشيبانغ والمغلفات (wrappers) إلى ملف قابل للتنفيذ مباشرة يحصل على النصوص البرمجية التي تمت مواجهتها كمعاملات بترتيب عكسي. على سبيل المثال، إذا كان الملف /bin/A ملفاً تنفيذياً بتنسيق ELF، والملف /bin/B يحتوي على الشيبانغ ، والملف /bin/C يحتوي على الشيبانغ ، فإن تنفيذ الملف /bin/C يُترجم إلى ، والذي يُترجم أخيراً إلى .

في أنظمة التشغيل المشتقة من سولاريس وداروين (مثل ماك أو إس)، يجب أن يكون الملف المحدد بواسطة interpreter ثنائياً تنفيذياً ولا يمكن أن يكون نصاً برمجياً بحد ذاته.

 أمثلة 
بعض أسطر الشيبانغ النموذجية:
 #! /bin/sh – تنفيذ الملف باستخدام صدفة بورن، أو صدفة متوافقة، يُفترض وجودها في دليل /bin.
 #! /bin/bash – تنفيذ الملف باستخدام صدفة باش.
 #! /usr/bin/pwsh – تنفيذ الملف باستخدام باورشل.
 #! /usr/bin/env python3 – التنفيذ باستخدام مفسر بايثون، مع استخدام مسار البحث الخاص ببرنامج env للعثور عليه.
 #! /bin/false – لا يفعل شيئاً، ولكنه يُرجع حالة خروج غير صفرية، مما يشير إلى الفشل. يُستخدم لمنع التنفيذ المستقل لملف نصي مخصص للتنفيذ في سياق محدد، مثل استخدام الأمر . من sh/bash، أو source من csh/tcsh، أو كملف .profile أو .cshrc أو .login.

قد تتضمن أسطر الشيبانغ خيارات محددة يتم تمريرها إلى المفسر. ومع ذلك، تختلف التطبيقات في سلوك تحليل الخيارات؛ ولضمان قابلية النقل، يجب تحديد خيار واحد فقط دون أي مسافات بيضاء مضمنة. توجد إرشادات إضافية حول قابلية النقل أدناه.

 الغرض 
تسمح توجيهات المفسر باستخدام النصوص البرمجية وملفات البيانات كأوامر للنظام، مما يخفي تفاصيل تنفيذها عن المستخدمين والبرامج الأخرى، وذلك من خلال إلغاء الحاجة إلى وضع بادئة المفسر قبل النص البرمجي في سطر الأوامر.

على سبيل المثال، لنفترض نصاً برمجياً يحتوي على السطر الأولي #! /bin/sh -x. يمكن استدعاؤه ببساطة عن طريق مسار الملف الخاص به، مثل some/path/to/foo،إذا سمحت بذلك بتات إذن exec للملف وبعض المعاملات، مثل bar و baz:

 some/path/to/foo bar baz

في هذه الحالة، يتم استدعاء /bin/sh محله، مع المعاملات -x، وsome/path/to/foo، وbar، وbaz، كما لو كان الأمر الأصلي:

 /bin/sh -x some/path/to/foo bar baz

تجعل معظم المفسرات أي وسائط إضافية متاحة للنص البرمجي. إذا كان /bin/sh عبارة عن صدفة متوافقة مع بوزيكس، فسيتم تقديم bar و baz للنص البرمجي كمصفوفة وسائط موضعية "$@"، وبشكل فردي كمعاملات "$1" و "$2" على التوالي.

لأن العلامة الأولية # هي الحرف المستخدم لتقديم التعليقات في لغة صدفة بوزيكس (وفي اللغات التي تفهمها العديد من المفسرات الأخرى)، يتم تجاهل سطر الشيبانغ بالكامل بواسطة المفسر. ومع ذلك، فإن الأمر متروك للمفسر لتجاهل سطر الشيبانغ، ولا تفعل جميعها ذلك؛ وبالتالي، فإن نصاً برمجياً يتكون من السطرين التاليين يخرج ببساطة كلا السطرين عند التشغيل:
 #! /bin/cat
 Hello world!

 نقاط القوة 
عند مقارنتها باستخدام قوائم الارتباط العامة بين امتدادات الملفات والتطبيقات المفسرة، تسمح طريقة توجيه المفسر للمستخدمين باستخدام مفسرات غير معروفة على مستوى النظام العام، ودون حقوق مسؤول النظام. كما أنها تسمح باختيار محدد للمفسر، دون تحميل زائد على نطاق الاسم الخاص بـ امتداد الملف (حيث يشير امتداد ملف واحد إلى أكثر من نوع ملف)، وتسمح بتغيير لغة تنفيذ النص البرمجي دون تغيير صيغة استدعائه بواسطة البرامج الأخرى. لا يحتاج مستدعو النص البرمجي إلى معرفة لغة التنفيذ لأن النص البرمجي نفسه مسؤول عن تحديد المفسر المراد استخدامه.

 قابلية النقل 

 موقع البرنامج 
يجب أن تحدد الشيبانغ مسارات مطلقة (أو مسارات نسبية لدليل العمل الحالي) للملفات التنفيذية للنظام؛ وهذا قد يسبب مشاكل في الأنظمة التي تمتلك تخطيطاً غير قياسي لملفات النظام. حتى عندما يكون للأنظمة مسارات قياسية إلى حد ما، فمن الممكن جداً لمتغيرات نفس نظام التشغيل أن يكون لها مواقع مختلفة للمفسر المطلوب. بايثون، على سبيل المثال، قد تكون في /usr/bin/python3، أو /usr/local/bin/python3، أو حتى شيء مثل /home/username/bin/python3 إذا تم تثبيته بواسطة مستخدم عادي.

توجد مشكلة مماثلة لـ صدفة بوزيكس، حيث تطلب بوزيكس فقط أن يكون اسمها sh، لكنها لم تفرض مساراً محدداً. القيمة الشائعة هي ، لكن بعض الأنظمة مثل سولاريس لديها الصدفة المتوافقة مع بوزيكس في /usr/xpg4/bin/sh. في العديد من أنظمة لينكس، يكون /bin/sh عبارة عن رابط ثابت أو رابط رمزي إلى /bin/bash، أي صدفة بورن أغين (BASH). استخدام صيغة خاصة بـ bash مع الحفاظ على شيبانغ يشير إلى sh هو أيضاً غير قابل للنقل.

بسبب هذا، يُطلب أحياناً تعديل سطر الشيبانغ بعد نسخ نص برمجي من حاسوب إلى آخر لأن المسار الذي تم ترميزه في النص قد لا ينطبق على الجهاز الجديد. لهذا السبب ولأن بوزيكس لا توحد أسماء المسارات، فإن بوزيكس لا توحد هذه الميزة. يمكن لأداة جنو أوتوكونف اختبار دعم النظام باستخدام الماكرو AC_SYS_INTERPRETER.

غالباً، يمكن استخدام البرنامج  للتحايل على هذا القيد من خلال تقديم مستوى من توجيه غير مباشر. يتم اتباع  بـ ، يليه الأمر المطلوب دون مسار كامل، كما في هذا المثال:
 #!/usr/bin/env sh

يعمل هذا في الغالب لأن المسار  يُستخدم بشكل شائع للأداة المساعدة ، وهي تستدعي أول  يتم العثور عليه في $PATH الخاص بالمستخدم، وعادة ما يكون .

هذا المثال المحدد (استخدام ) ذو فائدة محدودة: حيث أن لا  ولا  عالميان تماماً. بشكل أوسع، استخدام  لأي نص برمجي لا يزال يعاني من بعض مشاكل قابلية النقل مع أنظمة قديمة مثل OpenServer 5.0.6 و Unicos 9.0.2 التي تحتوي فقط على  وليس .

يؤدي استخدام  إلى توجيه غير مباشر في وقت التشغيل، مما قد يؤدي إلى تقليل أمان النظام؛ لهذا السبب يوصي بعض المعلقين بعدم استخدامه في البرمجيات المحزمة، وحجزه فقط "للأمثلة التعليمية".

 تقسيم المعاملات 
يتم تقسيم معاملات الأوامر بطرق مختلفة عبر المنصات.
بعض الأنظمة لا تقسم المعاملات؛ على سبيل المثال، عند تشغيل النص البرمجي بالسطر الأول:
 #!/usr/bin/env python3 -c
يتم التعامل مع جميع النصوص بعد المسافة الأولى كمعامل واحد، أي أنه سيتم تمرير  كمعامل واحد إلى ، بدلاً من معاملين. تشمل هذه الأنظمة لينكس، قسم "Interpreter scripts" و سيغوين.

نهج آخر هو استخدام مغلف. قدم FreeBSD 6.0 (2005) الخيار  لبرنامج  حيث غيّر سلوك قراءة الشيبانغ إلى عدم التقسيم. يخبر هذا الخيار  بتقسيم السلسلة بنفسه. تتضمن أداة جنو  منذ coreutils 8.30 (2018) هذه الميزة أيضاً. على الرغم من أن استخدام هذا الخيار يخفف من مشكلة قابلية النقل على جانب النواة مع التقسيم، فإنه يضيف شرط أن  يدعم هذا الامتداد المحدد.

 تفسير المحارف 
مشكلة أخرى هي النصوص البرمجية التي تحتوي على محرف إرجاع الرأس (carriage return) مباشرة بعد سطر الشيبانغ، ربما نتيجة لتحريرها على نظام يستخدم نهايات أسطر DOS (مثل مايكروسوفت ويندوز). تفسر بعض الأنظمة محرف إرجاع الرأس كجزء من أمر المفسر، مما يؤدي إلى رسالة خطأ.

 الرقم السحري 
الشيبانغ هو في الواقع نسخة مقروءة للبشر من رقم سحري في الملف التنفيذي، وسلسلة البايتات السحرية هي ، وهو الترميز المكون من حرفين في آسكي لـ . يتم اكتشاف هذا الرقم السحري بواسطة عائلة دوال "exec"، التي تحدد ما إذا كان الملف نصاً برمجياً أم ثنائياً تنفيذياً. سيؤدي وجود الشيبانغ إلى تنفيذ الملف التنفيذي المحدد، وعادة ما يكون مفسراً للغة النص البرمجي. زُعم أن بعض الإصدارات القديمة من يونكس تتوقع أن يتبع الشيبانغ العادي مسافة وشرطة مائلة ()، ولكن يبدو أن هذا غير صحيح؛ بدلاً من ذلك، تم السماح بالمسافات الفارغة بعد الشيبانغ بشكل تقليدي، وأحياناً تم توثيقها بمسافة، كما هو موضح في البريد الإلكتروني التاريخي لعام 1980 أدناه.

يتم تمثيل محارف الشيبانغ بنفس البايتين في ترميزات آسكي الموسعة، بما في ذلك صيغة التحويل الموحد-8، والذي يُستخدم بشكل شائع للنصوص البرمجية والملفات النصية الأخرى على أنظمة شبيهة يونكس الحالية. ومع ذلك، قد تبدأ ملفات UTF-8 بـ علامة ترتيب البايت (BOM) الاختيارية؛ إذا اكتشفت دالة "exec" تحديداً البايتات  و ، فإن وجود BOM () قبل الشيبانغ سيمنع تنفيذ مفسر النص البرمجي. توصي بعض الجهات بعدم استخدام علامة ترتيب البايت في نصوص بوزيكس (شبيهة يونكس)، لهذا السبب ولأجل توافقية أوسع واهتمامات فلسفية. بالإضافة إلى ذلك، علامة ترتيب البايت ليست ضرورية في UTF-8، حيث لا يعاني هذا الترميز من مشاكل ترتيب البايتات (Endianness)؛ فهي تخدم فقط لتعريف الترميز كـ UTF-8.

 أصل التسمية 
الملف التنفيذي الذي يبدأ بتوجيه مفسر يسمى ببساطة "نص برمجي" (Script)، وغالباً ما يُسبق باسم أو التصنيف العام للمفسر المقصود. قد يكون اسم شيبانغ (shebang) لهذين المحرفين المميزين قد أتى من تقليص غير دقيق لـ SHArp bang أو haSH bang، في إشارة إلى الاسمين النموذجين لهما في يونكس. نظرية أخرى حول sh في shebang هي أنها من الصدفة الافتراضية sh، التي يتم استدعاؤها عادةً بالشيبانغ. كان هذا الاستخدام سارياً بحلول ديسمبر 1989، وربما قبل ذلك.

 التاريخ 
تم تقديم الشيبانغ بواسطة دينيس ريتشي بين الإصدار السابع والثامن في مختبرات بل. تمت إضافته أيضاً إلى إصدارات BSD من أبحاث علوم الكمبيوتر في بيركلي (موجود في 2.8BSD وتم تنشيطه افتراضياً بحلول 4.2BSD). نظراً لأن الإصدار الثامن من يونكس لمختبرات AT&T Bell، والإصدارات اللاحقة، لم يتم إصدارها للجمهور، كان أول ظهور معروف على نطاق واسع لهذه الميزة في BSD.

إن غياب توجيه المفسر، ولكن مع دعم نصوص الشل، واضح في توثيق الإصدار السابع من يونكس في عام 1979، الذي يصف بدلاً من ذلك تسهيلاً في صدفة بورن حيث يتم التعامل مع الملفات ذات إذن التنفيذ بشكل خاص بواسطة الصدفة، والتي (أحياناً اعتماداً على الأحرف الأولية في النص البرمجي، مثل ":" أو "#") تفرخ صدفة فرعية تفسر وتنفذ الأوامر الموجودة في الملف. في هذا النموذج، تتصرف النصوص البرمجية فقط كأوامر أخرى إذا تم استدعاؤها من داخل صدفة بورن. محاولة تنفيذ مثل هذا الملف مباشرة عبر استدعاء النظام exec() الخاص بنظام التشغيل ستفشل، مما يمنع النصوص البرمجية من التصرف بشكل موحد كأوامر نظام عادية.

 نصوص الصدفة المحسنة في الإصدار الثامن 
في الإصدارات اللاحقة من الأنظمة الشبيهة بيونكس، تمت إزالة هذا التناقض. أدخل دينيس ريتشي دعم النواة لتوجيهات المفسر في يناير 1980، لـ الإصدار الثامن من يونكس، بالوصف التالي:

 From uucp Thu Jan 10 01:37:58 1980
 >From dmr Thu Jan 10 04:25:49 1980 remote from research

 The system has been changed so that if a file being executed
 begins with the magic characters #! , the rest of the line is understood
 to be the name of an interpreter for the executed file.
 Previously (and in fact still) the shell did much of this job;
 it automatically executed itself on a text file with executable mode
 when the text file's name was typed as a command.
 Putting the facility into the system gives the following
 benefits.

 1) It makes shell scripts more like real executable files,
 because they can be the subject of 'exec.'

 2) If you do a 'ps' while such a command is running, its real
 name appears instead of 'sh'.
 Likewise, accounting is done on the basis of the real name.

 3) Shell scripts can be set-user-ID.

 4) It is simpler to have alternate shells available;
 e.g. if you like the Berkeley csh there is no question about
 which shell is to interpret a file.

 5) It will allow other interpreters to fit in more smoothly.

 To take advantage of this wonderful opportunity,
 put

    #! /bin/sh

 at the left margin of the first line of your shell scripts.
 Blanks after ! are OK.  Use a complete pathname (no search is done).
 At the moment the whole line is restricted to 16 characters but
 this limit will be raised.

 ميزة نص الصدفة غير المسماة 
لم يعط مبتكر الميزة اسماً لها، مع ذلك:

From: "Ritchie, Dennis M (Dennis)** CTR **" <dmr@[redacted]>
To: <[redacted]@talisman.org>
Date: Thu, 19 Nov 2009 18:37:37 -0600
Subject: RE: What do -you- call your #!<something> line?

 I can't recall that we ever gave it a proper name.
It was pretty late that it went in--I think that I
got the idea from someone at one of the UCB conferences
on Berkeley Unix; I may have been one of the first to
actually install it, but it was an idea that I got
from elsewhere.

As for the name: probably something descriptive like
"hash-bang" though this has a specifically British flavor, but
in any event I don't recall particularly using a pet name
for the construction.

انتشر دعم النواة لتوجيهات المفسر إلى إصدارات أخرى من يونكس، ويمكن رؤية تطبيق حديث في مصدر نواة لينكس في fs/binfmt_script.c.

تسمح هذه الآلية باستخدام النصوص البرمجية في أي سياق تقريباً يمكن فيه استخدام البرامج المترجمة العادية، بما في ذلك كبرامج نظام كاملة، وحتى كمفسرات لنصوص برمجية أخرى. كتحذير، على الرغم من ذلك، حدت بعض الإصدارات المبكرة من دعم النواة من طول توجيه المفسر إلى ما يقرب من 32 حرفاً (فقط 16 في تطبيقه الأول)، أو كانت تفشل في تقسيم اسم المفسر عن أي معلمات في التوجيه، أو كانت بها عيوب أخرى. بالإضافة إلى ذلك، تسمح بعض الأنظمة الحديثة بتقييد الآلية بأكملها أو تعطيلها لأغراض أمنية (على سبيل المثال، تم تعطيل دعم set-user-id للنصوص البرمجية في العديد من الأنظمة).

لاحظ أنه، حتى في الأنظمة ذات الدعم الكامل من النواة لـ الرقم السحري #!، فإن بعض النصوص البرمجية التي تفتقر إلى توجيهات المفسر (على الرغم من أنها عادة ما تظل تتطلب إذن التنفيذ) لا تزال قابلة للتشغيل بفضل معالجة النصوص البرمجية القديمة لصدفة بورن، والتي لا تزال موجودة في العديد من أحفادها الحديثة. يتم بعد ذلك تفسير النصوص البرمجية بواسطة الصدفة الافتراضية للمستخدم.

 ملاحظات 

 المراجع 

 وصلات خارجية 
 تفاصيل حول آلية الشيبانغ في مختلف نكهات يونكس (بالإنجليزية)
 #! - حقيقة يونكس كما أعرفها (نهج أكثر عمومية) (بالإنجليزية)
 مقال FOLDOC عن الشيبانغ (بالإنجليزية)

تصنيف:يونكس
تصنيف:لغات برمجة نصية