اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'script'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 14 نتائج

  1. إن مصمم الرسوميات فنان مبدع، يحوّل أفكاره وأفكار عملائه إلى تحفة فنية تهدف إلى إيصال الفكرة الرئيسية إلى الجمهور بأسلوب فني وطريقة سلسة ليتردد صداها بين الناس. ويستثمر المصمم الألوان والخطوط وجميع العناصر الرسومية في سبيل ولادة تحفته الفنية وبلورتها. ويعد عنصر النص واحدًا من أهم العناصر الرسومية وأكثرها تأثيرًا، وهو فن جميل مميز يخلّد الأفكار في عقول الناس أكثر من أي عنصر آخر. لذلك يجب فهم ومعرفة القواعد الأساسية في العمل على هذا العنصر لتحقيق الاستفادة القصوى من قوته وتأثيره. ما هو عنصر النص أو أسلوب الطباعة التيبوغرافي؟ التيبوغرافي Typography هو فن حقيقي يتضمن ترتيب الكلمات والحروف بطرق وأساليب معينة بغية إحداث التأثير وإيصال الرسالة للناس. ويضيف المصمم النص إلى أي تصميم عند الحاجة لإضافة محتوى خاص مع المحافظة على جمالية وأسلوب التصميم العام، ويعد العنصر الحسم في إنشاء وتصميم أي علامة تجارية، لأنه يمثّل الهوية الأبرز للعلامة التجارية والتي ستساهم في نجاحها واستمراريتها ورسوخها في أذهان الناس. كما يعد العنصر الأهم في تصميم صفحات الويب والكتيبات والمنشورات الإعلانية، حيث يساهم الاستخدام الصحيح والمميز لهذا العنصر في تحقيق نقلة نوعية للعلامة التجارية وتمكين تأثيرها على الجمهور، بينما على الجانب الآخر سيسبب الاستخدام الخاطئ والتصميم السيئ إلى نفور الجمهور منها وعدم قبوله لأفكارها ورسائلها. المبادئ الأساسية لفن تصميم النصوص كما لتصميم الرسوميات مبادئ أساسية يجب مراعاتها واستخدامها استخدامًا صحيحًا لتحقيق الفائدة الأكبر من التصميم وإيصال الرسالة للجمهور، فإن فن تصميم النصوص له مبادئ يجب الانتباه لها ومراعاتها واستخدامها لتحقيق الاستفادة القصوى من تأثير النص والمحتوى على المشاهدين، ويتشارك فن النصوص عدة مبادئ مع تصميم الرسوميات. المحارف والخطوط Typeface and Fonts: يجب الانتباه جيدًا عند انتقاء نوعية الخط المستخدم بحيث يجب أن تكون مميزة للعلامة التجارية أو للهدف من التصميم، ويجب أن نستخدم عائلة الخط ذاتها في التصاميم المتعددة للهدف ذاته مثل تصميم الهوية البصرية لعلامة تجارية وتصميم المنشورات الترويجية على مواقع التواصل الاجتماعي، مع مراعاة وزن الخط وتأثيره النفسي على القارئ حيث يختلف تأثير الخط الثخين عن سواه على سبيل المثال، ويمكن استخدام خطوط من عائلات خطية مختلفة شريطة التوافق فيما بينها. وللعلم فقط فالمحرف هو نوعية الخط فقط مثل Arial والخط هو تفصيل نوعية الخط مثل Arial Bold 12point. انسيابية السطور Leading: وهي المسافة بين السطور بحيث يجب أن تكون موحدة وغالبًا ما تكون بارتفاع أعلى من ارتفاع خط النص نفسه. التتابع Letter Spacing: وهي المسافة الموجودة بين الكلمات في النصوص العربية وبين الحروف ذاتها في النصوص اللاتينية. طول سطر النص Line length: وهو الطول المستخدم لكل سطر في النص، فلا يجب أن يكون ممتدًا من بين حافتي التصميم ولا أن يكوّن من النص عمودًا نحيفًا. الهرمية Hierarchical: وهو نفس المبدأ الخاص بالتصميم ولكنه يتعلق هنا بالنص فقط، حيث يجب ترتيب النصوص بحسب الأهمية فيكون النص الأهم هو الأثقل من ناحية الوزن البصري مثل أن يكون أكبر حجمًا وأبرز لونًا وأثخن وغير ذلك، ثم النص الذي يليه من حيث الأهمية يجب أن يكون أخف من ناحية الوزن البصري، ثم الذي يليه وهكذا. اللون Color: يساعد على زيادة بروز النص وتأثيره مع الانتباه لقواعد الألوان وتطبيق أسسه الصحيحة على النص. المحاذاة Alignment: هو التأثير الأبرز في تحسين جماليات تصميم النصوص ويجب تطبيق المحاذاة على محور معين ضمن التصميم بطريقة مدروسة. التباين Contrast: لا يتعلق الأمر هنا بتباين ألوان النص مع محيطه أو مع بقية النصوص فقط، بل ويتعلق بتباين الأحجام والمسافات والمواقع أيضًا. أنواع الخطوط يوجد العديد من أنواع الخطوط المستخدمة في كتابة المحتوى وتصميم الرسوميات، وتتميز الحضارات المختلفة بفنون الكتابة اليدوية بحيث تتباهى بخطوطها الأصيلة المخطوطة يدويًّا وتعتبرها فنًا أصيلًا يمثّل ثقافة وماضي ومستقبل تلك الحضارة. إلا أنه فن يحتاج موهبة وتدريبًا وعملًا دؤوبًا حتى يصل الدارس فيه إلى مستوى الخطاط المتمكن، ويعد الخط العربي من أبرز فنون الكتابة اليدوية في التاريخ، حيث تزينت به المخطوطات والتصاميم المعمارية المختلفة، وإضافته إلى التصاميم الرسومية العربية يضيف جمالًا وطابعًا خاصًا لأي تصميم وخصوصًا في الشعارات والمنشورات الإعلانية. لكن فن الخط العربي اليدوي موهبة لا يتمتع بها الكثيرون، لذلك سنعتمد أكثر على الخطوط المصممة الجاهزة التي نستخدمها في الكتابة ضمن أجهزة الحاسوب وهي ما يطلق عليه مصطلح (الخطوط المحوسبة Computerized fonts)، ويوجد من هذه الخطوط أنواع وتختلف باختلاف اللغة المستخدمة أيضًا. الخطوط العربية تتألف الخطوط العربية من أنواع أساسية تتفرع عنها بقية الخطوط المعروفة وهي كثيرة ومن أهمها الكوفي، الثلث، النسخ، الفارسي، الديواني، الرقعة، المغربي والحر وغيرها الكثير، وسنتعرّف تاليًا على أهمها. الخط الكوفي: من أقدم الخطوط في بلاد العرب، ويمثل مظهرًا من مظاهر جمال الفنون العربية، وقد تسابق الكُتَاب في تطويره والتفنن في زخرفة حروفه، وله عشرات الأنواع المتفرعة عنه بما قد يتجاوز الخمسين نوعًا، من بينها البسيط، الفاطمي، الإيراني، المورّق، المزخرف، المعماري والكوفي المربع. هذه صور تمثل بعضًا من أنواع هذا الخط. وهنا بعض الخطوط الحاسوبية المشتقة من الخط الكوفي. خط الثلث: خط الثلث هو أصل الخطوط العربية وأجملها وأصعبها، استخدم في تزيين الجوامع والمحاريب والقباب وبدايات المصاحف، كما استخدم في عناوين الكتب، وأسماء الصحف والمجلات. وهذه بعض الخطوط الحاسوبية المشتقة من خط الثلث. خط النسخ: استخدم في كتابة المصحف الشريف بعد الخط الكوفي، ويتميز عن خط الثلث بأنه أكثر قاعدية وأقل صعوبة، فحروفه أصغر وأبسط في طريقة الكتابة، وهو أوضح في القراءة والكتابة. يعد الأكثر استخدامًا حاليًا في عالمنا المعاصر، بعد أن كتبت به المصاحف، كما اعتمدته دور النشر في كتابة نصوص الكتب والمخطوطات والمطبوعات، والصحف والمجلات، والكتابة الرقمية عبر برامج الحاسوب وصفحات الإنترنت. وهذه بعض الخطوط الحاسوبية المشتقة من خط النسخ. الديواني: يتميّز باستدارة حروفه وبمرونة التقاء الحروف وتلاصقها، فهو خط لين مطواع، وسهل الاستخدام. قام الأتراك بتطوير هذا الخط في عهد السلطان محمد الفاتح ووضعت قواعده بعد فتح القسطنطينية ببضع سنوات. وهذه بعض الخطوط الحاسوبية المشتقة من الخط الديواني. الفارسي: عُرف هذا الخط عند العرب بالخط الفارسي نسبةً للفرس وعرف عند الأتراك بخط التعليق وهو الخط الرئيسي في الهند وإيران وباكستان وأفغانستان. ويتميز بأن خطوطه ليست مستقيمة فكل الحروف بها انحناءات. وهذا خط حاسوبي مشتق من الخط الفارسي. الرقعة: يعد من أبسط الخطوط وأقلها تقييدًا فلا يوجد به الكثير من التحسينات الشكلية والتزيين، ولا الكثير من الميلان والتدوير، وهو من أحدث أنواع الخطوط العربية، ابتكره العثمانيون، ويتميز بالاستقامة والبساطة وسهولة الكتابة والقراءة والبعد عن التعقيد، وحروف هذا الخط قصيرة، وتستهلك مساحة صغيرة موازنة بأنواع الخطوط الأخرى. ونتيجة لهذه السمات فهو خط عملي واضح في كتابة اللافتات والدعاية والإعلان واستعمله الناشرون في كتابة عناوين الكتب والصحف والمجلات. وهذه بعض الخطوط الحاسوبية المشتقة من خط الرقعة. المغربي: انتشر الخط المغربي في شمالي أفريقيا، وله عدة أنواع وهي الكوفي المغربي، الثلث المغربي، المبسوط، المجوهر والمسند. وهذه بعض الخطوط الحاسوبية المشتقة من الخط المغربي. الحر: هو خط حديث لا يخضع لقواعد محددة، وإنما يخضع لذوق ورؤية كل خطاط أو مصمم، وقد قام بعض الخطاطين العرب بوضع قواعد للخط الحر، فيما تحفّظ آخرون على هذه القواعد باعتبار الخط حرًّا ولا يخضع لقواعد. يلجأ العديد من مصممي الإعلانات لاستخدام الخط الحر في تصميم شعارات الشركات لما له من جمالية ومرونة في تشكيل الشعار وتطويع حروفه لتشكيل لوحة فنية معبرة عن مضمون الشعار. وهذه بعض الخطوط الحاسوبية المشتقة من الخط الحر. الخطوط اللاتينية وهي الخطوط المستخدمة في اللغات الغربية مثل الإنجليزية والفرنسية وغيرها، ولهذه الخطوط أنواع أساسية يطلق عليها اسم عائلات الخطوط ويُشتق منها العديد من الخطوط، ومن أهم هذه الخطوط Serif وSans Serif وSlab Serif وScript وDecorative. Serif: تعد خطوط Serif تقليدية وسهلة القراءة للغاية، لذا فهي عادةً أفضل نوع من الخطوط لاستخدامها للعناوين والتصاميم الكبيرة، وهي شائعة لتصاميم شعارات العلامات التجارية، إلا أن ذلك لا ينطبق دائمًا على شاشات الهاتف المحمول. وكلمة Serif تعني تلك الأجزاء النافرة من الحروف بينما Sans Serif تعني عدم وجود تلك الأجزاء. استُخدم هذا النوع من الخطوط بما في ذلك جميع الخطوط التابعة لعائلته في العناوين و في شعارات علامات تجارية شهيرة مثل هاربرز بازار Harper’s Bazaar ومجلة إيللي Elle Magazine وجيورجيو أرماني Giorgio Armani. ومن أشهر الخطوط التابعة لعائلة Serif خطوط Garamond، Baskerville وDidot. بعض من خطوط Serif. Sans Serif: تزايدت شعبية هذه الخطوط بصورة كبيرة في السنوات الأخيرة، وتتميز بالشخصية الرئيسية دون أي حدود نهائية زخرفية. يُنظر إلى هذه الأنواع من الخطوط على أنها من أكثر خيارات الخطوط وضوحًا وبساطة وحداثة، وتعد أفضل خط يمكن استخدامه لقراءة النص على الشاشات. يسهل على الأجهزة عرض خطوطها الواضحة والحادة، وتظهر بوضوح على الشاشة البيضاء الساطعة. وقد استخدمت هذه العائلة من الخطوط مجموعة من العلامات التجارية الشهيرة أمثال تارجت Target وباناسونيك Panasonic وجيب Jeep وتويوتا Toyota، كما بدّلت جوجل Google شعارها من خط Serif إلى خط من Sans Serif عام 2015. من أشهر خطوط هذه العائلة Futura، Graphik، Circular و GT Americ. بعض من خطوط Sans Serif. Slab Serif: وهي فرع من عائلة خطوط Serif الشاملة التي تحدثنا عنها سابقًا. إلا أنها مربعة ومتكتّلة بشكل أكبر من خطوط Serif التقليدية، كما أنها أثخن وأكثر حداثة وتعد خيارًا جيدًا للعلامات التجارية التي تتميز بالجرأة والدرامية، ومن هذه العلامات التجارية هوندا Honda، سوني Sony وفولفو Volvo. ومن أشهر الخطوط التي تنتمي لهذه العائلة Sentinel، Adelle، Shift و Bodoni Egyptian. بعض من خطوط Slab Serif. Script: هو خط يتميز بالرسمية والشكليات ويحاكي الكتابة بخط اليد إلى حد ما. ويتوفر منه خطوط ذات ميزات متنوعة من الخيالي والمتطور إلى العصري والمريح. يعد من أقل الخطوط استخدامًا في التصاميم كونه لا يناسب النصوص الطويلة، لكنه جيد إلى حد ما في العناوين والشعارات. ومن أشهر العلامات التي تستخدم هذه النوعية من الخطوط إنستغرام Instagram، بي إنترست Pinterest، كوكاكولا Coca-Cola وكاديلاك Cadillac. ومن أشهر الخطوط التي تنتمي لهذه العائلة Southern Aire، Milles، French Script و Billenia. بعض من خطوط Script. Decorative: وتعني الخطوط الزخرفية، وهي مميزة في التصاميم الزخرفية والفنية أكثر مما تستخدم في النصوص والعناوين، وتستخدم في الشعارات والمنشورات الإعلانية كنوع من التزيين، وغالبًا ما تكون من أكبر عناصر التصميم لإبراز زخارفها. لها نمطان منتشران وهما النمط القديم التاريخي والحديث المستقبلي. ومن أشهر الشعارات التي استخدمت هذه الخطوط تويز آر أس Toys R Us، ليجو Lego وفانتا Fanta. ومن أشهر خطوط هذه العائلة Helios وThe Roseberry وMotters و Xaviera. بعض من خطوط Decorative. قواعد تصميم النص وتتضمن التطبيق العملي لمبادئ تصميم النص مع الإشارة إلى أهم ما يجب اتباعه في عملية التصميم. التقنين Kerning ويقصد بهذا المصطلح ضبط المسافة بين الحروف، قد يبدو لك أن هذا الأمر مستبعد للنصوص العربية ومنتشر في النصوص اللاتينية، هذا صحيح نسبيًا، ولكن أحيانًا قد يضيف المصمم إطالات غير ضرورية على النص ظنًّا منه أنه يملأ مساحة التصميم بطريقة جميلة إلا أنه فعليًّا يدمّر التصميم، فكلمة (دليل) المكتوبة بهذه الطريقة أجمل بكثير من الطريقة التالية (د لـــيــــــــــل) وخصوصًا ضمن التصاميم الفنية، كما أن بعض المصممين لا ينتبهون لتفاصيل دقيقة وهم في عجالة من أمرهم مثل مسألة المسافة الفاصلة بين الحروف والتي يتم ضبطها من أدوات النصوص في برامج التصميم المختلفة، وهذه أمثلة عن ما نتحدث عنه. انعدام التقنين عبر زيادة التباعد في الحروف يؤدي إلى تصميم سيء وطبعًا تبقى مسألة مراعاة التقنين في النصوص العربية نادرة الحدوث إذا ما قارنّاه بالنصوص اللاتينية، حيث تستخدم الحروف المنفصلة في الكتابة وهو ما يسبب مشاكل كثيرة في ضبط التقنين، فيجب مراعاة المسافة بين الحروف بدقة وتوازن. خبراء التصميم يصرّون أنه لا يجب أن نعتمد على التقنين الآلي لبرامج التصميم المختلفة وأنه يجب علينا تقنين النصوص بأنفسنا وخصوصًا لنصوص العناوين والنصوص كبيرة الحجم، لأن مشاكل التقنين تبرز واضحة بها أكثر من النصوص صغيرة الحجم. يمكنك أن تدرّب نفسك على التقنين الصحيح من خلال موقع KERNTYPE والذي يمنح درجات تقديرية لقاء صحة عملية التقنين التي تنفذها. صورة توضح النص بدون ومع تقنين – الصورة من مدونة خطوط أدوبي التواصل بين الخطوط Font Communication إن أسوأ ما يقوم به المصمم لاختيار الخطوط المناسبة للتصميم هو البحث العشوائي أو استعراض كافة الخطوط في مكتبة الخطوط المتوفرة على حاسوبه، لأن ذلك سيبعثر أفكاره ويشتت تركيزه على الاختيار الصحيح للخطوط خصوصًا إن كان يعمل على تصميم يتضمن أكثر من نص منفصل وعليه اختيار نوعية خط لكل نص. في هذه الحالة يجب التركيز على أن تكون الخطوط من نمط متماثل، مثل أن تكون من نفس عائلة الخطوط كالخطوط المغربية أو الكوفية، أو أن تكون من نفس أسلوب الخط كخطوط قديمة تاريخية أو خطوط عصرية، وهو ما يحقق التواصل بين الخطوط ويبقي التصميم متناسقًا ومتجانسًا. في الصورتين التاليتين مثالين عن الاختيار السيء والاختيار الصحيح لنمط الخطوط. لاحظ الخط المستخدم في العنوان غير ملائم لمعنى النص وغير متناسق مع الخط المستخدم في العنوان الثاني الخطوط هنا ملائمة للمحتوى ومتناسقة مع بعضها بالنسبة لكلا العنوانين تطبيق المحاذاة Alignment المحاذاة من المبادئ المهمة في تصميم الرسوميات وفي قواعد استخدام النص وأسلوب الطباعة في التصميم. تطبيقه بطريقة صحيحة ينتج جمالية ومثالية في التصميم، وعدم تطبيقه يؤدي إلى تصميم غير مريح. يجب تطبيق المحاذاة على محور محدد من قبل المصمم مهما كان اتجاه هذا المحور أو زاوية ميلانه. في المثالين التاليين تظهر لنا أهمية تطبيق المحاذاة على النصوص في التصميم. تطبيق المحاذاة بطريقة صحيحة منح تصميم النص أناقة وجمالية وراحة للنظر عدم تطبيق المحاذاة أساءت للتصميم ككل وأصبح غير مريح للنظر تطبيق مبدأ الهرمية Hierarchy سبق وأن تحدثنا عن هذا المبدأ مرارًا وهو الذي يؤدي إلى توجيه المشاهد ضمن مساحة التصميم من الأهم إلى الأقل أهمية، ولعل أكثر ما ينطبق عليه هذا المبدأ هو عنصر النص، حيث يجب أن يكون العنوان الرئيسي هو الأكثر بروزًا وظهورًا وجذبًا للانتباه لأنه الأهم بين باقي النصوص، ثم تتالى بقية النصوص في الحجم والموضع من حيث الأهمية. لاحظ التدرج من حيث الأهمية من العنوان الرئيسي بالتتالي. أهمية الحجم Size من العوامل المهمة لنجاح تصميم ما لغرض ترويجي وإعلاني جذب انتباه المشاهد على الفور، ففي أفضل الأحوال لديك ثانية أو ثانيتين لجذب انتباه شخص ما في عالم الطباعة، إذا فاتتك هذه الفرصة، فقد فقدت عميلك المحتمل. في المثال التالي صممت إعلانًا ترويجيًا بنمطين، الأول في الأعلى بدون مراعاة مسألة الحجم، حيث كان النص بالكامل بنفس الحجم، ولمعرفة مضمون رسالة التصميم يجب عليك قراءة كامل المحتوى، فلو كان المحتوى أطول فإن هناك احتمالًا كبيرًا أن يصاب العميل بالملل ويغادر دون المتابعة وبذلك لن تصله الرسالة. ركّزت في التصميم الثاني في الأسفل على زيادة حجم النص الأهم وهو (الربح) والذي يجذب اهتمام المشاهد على الفور ويفهم الرسالة بدون قراءة كامل المحتوى، إلا أن جذب الاهتمام هذا، سيجبر المشاهد على قراءة كامل المحتوى رغبة منه في معرفة التفاصيل وعندها تصله الرسالة كاملة. لاحظ المثال في الأعلى غير مثير للاهتمام بينما في المثال الثاني في الأسفل الأمر مختلف مع أن المحتوى متطابق تمامًا. التركيز في الفقرات النصية Emphasis عندما تصمم موقعًا على الويب أو نشرة إعلانية تتضمن نصوصًا طويلة أو فقرات نصية كبيرة نسبيًا، يجب أن نتجنب حالة الملل التي قد يشعر بها القارئ نتيجة طول الفقرة ومن ثم حالة هروب القارئ بسبب الملل وعدم إكماله القراءة وبالتالي عدم وصول الرسالة كاملة وصحيحة إليه. لذلك يجب إحداث بعض التعزيزات على النص من خلال التركيز على النقاط المهمة ضمن النص، ويمكن إحداث ذلك عبر زيادة وزن الخط (ثخين) أو إمالته أو حتى تغيير لونه، وبذلك نحقق التركيز وجذب الاهتمام ونبعد الملل عن القارئ. في المثال التالي استخدمت النص ذاته مرتين، في الأولى لم أطبق التركيز ضمن النص، بينما استخدمت التركيز في الثانية والذي يبدو أكثر إثارة للاهتمام، ويشد القارئ إلى متابعة قراءته عكس الأولى. لاحظ أن النص العلوي ممل وغير مثير للاهتمام بعكس السفلي – النص مقتبس من ويكيبيديا تجنب المسافات الزائدة Distances قد يلجأ بعض المصممين أثناء كتابة نص فقرة إعلانية أو منشور إعلاني إلى فكرة توسيع المسافات بين الكلمات لملء مساحة التصميم، خصوصًا إذا كان النص قليلًا ولا يكفي لملء مساحة التصميم. يعد هذا الأمر خطأً كبيرًا، إياك والوقوع فيه، إذ ينم ذلك عن قلة معرفة وخبرة في التصميم ويجعل المنشور أو الإعلان رديء المنظر. إن كان لديك نقص في المحتوى وتوجد مساحة فارغة ضمن التصميم فاستغل تلك المساحة بخلفية ملونة أو صورة أو عنصر رسومي، فذلك أفضل ويُشعر المشاهد للنص بالراحة أكثر. لاحظ النص العلوي غير مريح للنظر وللقراءة معًا ويشعرك بالغرابة – النص مقتبس من ويكيبيديا تجنب الأرامل النصية والأيتام النصية هذان المصطلحان مستخدمان بكثرة في الأوساط الغربية وتحديدًا بين المصممين وكتّاب المحتوى. ما المقصود بهذين المصطلحين؟ عندما تكتب فقرة ما في التصميم ثم تنتهي المساحة المحددة طوليًّا لكتابة الفقرة مثل مربع نصي أو ما شابه وتضطر للمتابعة بالكتابة عبر الانتقال لعمود نصي أو مربع نصي جديد، ويكون هناك سطر أو سطرين فقط في المساحة النصية الجديدة، فهذه تسمى بالأرامل النصية. وعندما تكون هذه الفقرة الزائدة مجرد كلمة أو كلمتان، فهذه تسمى بالأيتام النصية. وتجنب هذه الحالتين بسيط، إما عبر التلاعب بالنص نفسه أو بالمسافة النصية كزيادة العرض قليلًا أو زيادة الطول إن أمكن، أو التلاعب بحجم النص بمقدار قليل، إلى أن تختفي هذه الظاهرة وتحل المشكلة. لاحظ الأيتام النصية (1) في الصفحة اليسرى والأرامل النصية في اليمنى (2) وهو ما يجب تجنبه. تجنب الأخطاء الإملائية واللغوية أهم ما يجب أن ننتبه له نحن معشر المصممين في التصاميم ذات المحتوى الكثيف نسبيًا حتى وإن كان سطرًا واحدًا، هو الانتباه إلى الأخطاء الإملائية واللغوية، لأن ذلك قد ينسف تصميمك كله في حال الوقوع في خطأ من هذا النوع وخصوصًا في اللغة العربية. لذلك يجب أن نهتم بثقافتنا اللغوية وأن نتابع دومًا كل المعلومات المتعلقة باللغة العربية وقواعدها مثل أنواع الجمل والأزمنة والهمزات والجمع والتثنية وقواعد التشكيل المختلفة وغيرها. لاحظ الفرق الشاسع بين الإعلانين من حيث التدقيق اللغوي، أنت بالتأكيد لن تتقبل الإعلان الأول بسلاسة. خاتمة لاحظنا كيف أن النص وأسلوب الطباعة له تأثير هائل على جودة التصميم وإيصال الرسالة بأفضل طريقة ممكنة إلى الجمهور، ولكن حتى نتمكن من استخدام عنصر النص وأسلوب الطباعة بالطريقة الأمثل لتحقيق الهدف علينا مراعاة مبادئ وقواعد استخدامها، وتجنب المحاذير والأخطاء التي قد تؤدي إلى عكس النتيجة المرجوة من الإعلان، بحيث تؤدي إلى نفور الجمهور بدلًا من جذبهم وإثارة اهتمامهم بالتصميم وإيصال الرسالة. مع ذلك فإن مراعاة القواعد وتطبيق المبادئ وتجنب الأخطاء ليس صعبًا ومن اليسير القيام بذلك بمجرد التركيز قليلًا على هذه القواعد والمبادئ.
  2. سنلقي في هذا الدرس نظرةً إلى آلية التعامل مع الأخطاء و الإشارات أثناء تنفيذ السكربتات. يُقاس الفرق بين البرمجة الجيدة والتعيسة عادةً بمدة استقرار البرنامج ومرونته، أي قابلية تعامل البرنامج مع الحالات التي لا تسير فيها الأمور على ما يرام. حالة الخروج تتذكر من دروسنا السابقة أنَّ كل برنامج مكتوب بطريقة جيدة سيُعيد حالة خروج عندما ينتهي تنفيذه؛ فإذا انتهى تنفيذ البرنامج بنجاح، فستكون حالة الخروج مساويةً للصفر، وإن كانت حالة الخروج مساوية لقيمة مختلفة عن الصفر، فهذا يدلّ أنَّ البرنامج قد واجهة مشكلةً ما منعته من إتمام مهمته. من المهم جدًا التحقق من حالة خروج البرامج التي تستدعيها في سكربتاتك، ومن المهم أيضًا أن تُعيد سكربتاتك حالة خروج مفيدة عندما تنتهي. لقد مرّ عليّ مدير أنظمة يونكس قد كتب سكربتًا لنظام إنتاجي يحتوي على السطرين الآتيين: # Example of a really bad idea cd $some_directory rm * هذه طريقة سيئة جدًا لكتابة البرامج، لأنها تعمل بشكلٍ جيد لو لم يحدث أيّ خطأ. فالسطر الأول ينقل مجلد العمل الحالي إلى المسار الموجود في المتغير ‎$some_directory ثم يحذف جميع الملفات الموجودة في ذاك المجلد؛ وهذه هي الحالة الطبيعية لتنفيذ السكربت، لكن ماذا يحدث لو لم يكن المسار الموجود في المتغير ‎$some_directory موجودًا؟ سيفشل -في هذه الحالة- تنفيذ الأمر cd ثم سيُنفِّذ السكربتُ الأمرَ rm في مجلد العمل الحالي، وهنا ستقع الكارثة! بالمناسبة، واجه سكربت مدير الأنظمة البائس هذه المشكلة ودمَّر جزءًا كبيرًا مهمًا من النظام الإنتاجي؛ لا تدع ذلك يحدث لك! مشكلة السكربت السابق أنَّه لم يتحقق من حالة خروج الأمر cd قبل الاستمرار وتنفيذ الأمر rm. التحقق من حالة الخروج هنالك عدِّة طرائق تستطيع فيها الحصول على حالة الخروج والتصرف وفقًا لها. أول طريقة هي معاينة محتويات متغير البيئة ‎$?‎، الذي يحتوي على حالة خروج آخر أمر مُنفَّذ. يمكنك رؤية ذلك في المثال الآتي: $ true; echo $? 0 $ false; echo $? 1 تذكَّر أنَّ الأمرَين true و false لا يفعلان شيئًا سوى الانتهاء بحالة خروج تساوي 0 و 1 على التوالي وبالترتيب. وعبر استخدامهما سنرى كيف يُعيد المتغير ‎$?‎ حالة الخروج لآخر أمر مُنفَّذ. نستطيع كتابة السكربت بهذه الطريقة بعد التحقق من حالة الخروج: # Check the exit status cd $some_directory if [ "$?" = "0" ]; then rm * else echo "Cannot change directory!" 1>&2 exit 1 fi تفحصنا محتوى الأمر cd، وإن كان لا يساوي الصفر، فسيطبع رسالة خطأ في مجرى الخطأ القياسي (standard error stream) وسينتهي تنفيذه مع ضبط حالة الخروج إلى 1. صحيح أنَّ النسخة السابقة تقدِّم حلًا لمشكلتنا، إلا أنَّ هنالك طرائق أفضل ستقلل مقدار الكتابة التي نحتاج لها. سنستخدم في المثال الآتي العبارة الشرطية if مباشرةً، لأنَّها تحقق من حالة خروج الأمر الذي يليها ثم تتصرف وفقًا لذلك. يمكننا إعادة صياغة السكربت كالآتي: # A better way if cd $some_directory; then rm * else echo "Could not change directory! Aborting." 1>&2 exit 1 fi تحققنا هنا أنَّ تنفيذ الأمر cd قد نجح، وبعد ذلك سينُفّذ الأمر rm؛ أو ستظهر رسالة خطأ فيما عدا ذلك وينتهي البرنامج بحالة خروج تساوي 1، مما يشير إلى حدوث مشكلة أثناء التنفيذ. دالة خروج عند حدوث خطأ لمّا كنّا نتحقق من الأخطاء مرارًا وتكرارًا في برامجنا، فمن المعقول أن نكتب دالةً لإظهار الأخطاء، مما يوفِّر علينا بعض الكتابة ويُنمّي إحساس الكسل لدينا :-) . # An error exit function error_exit() { echo "$1" 1>&2 exit 1 } # Using error_exit if cd $some_directory; then rm * else error_exit "Cannot change directory! Aborting." fi معاملات التحكم: "و" AND وَ "أو" OR يمكننا تبسيط السكربت كثيرًا باستخدام معاملَي التحكم "AND" و "OR"، وسأقتبس الفقرة الآتية من صفحة دليل bash لشرح آلية عملهما: سنستعمل الأمرَين true و false مجددًا لكي نشاهد آلية التعامل مع AND و OR عمليًا: $ true || echo "echo executed" $ false || echo "echo executed" echo executed $ true && echo "echo executed" echo executed $ false && echo "echo executed" $ باستخدام هذه التقنية، يمكننا إعادة كتابة نسخة مختصرة أكثر من السكربت السابق: # Simplest of all cd $some_directory || error_exit "Cannot change directory! Aborting" rm * إن لم يكن إنهاء البرنامج مطلوبًا، فيمكننا كتابة السكربت بالصيغة الآتية: # Another way to do it if exiting is not desired cd $some_directory && rm * صحيحٌ أننا أخذنا جميع الاحتياطات الممكنة في مثال cd، إلا أنني أود أن أشير أنَّ الشيفرة يمكن أن تتعرض للمشاكل البرمجية الشائعة، خصوصًا إذا كُتِبَ اسم المتغير الذي يحتوي على مسار المجلد الذي نريد حذف محتوياته بشكلٍ خاطئ. ففي هذه الحالة ستضع الصَدَفة قيمةً فارغةً بدلًا من اسم المتغير وسينتج تنفيذ الأمر cd، لكنه سينتقل إلى مجلد المنزل للمستخدم الحالي، ثم سيحذف كل ما فيه! تحسين دالة الخروج عند حدوث خطأ هنالك عددٌ من التحسينات التي نستطيع إجراءها على الدالة error_exit، أود أن أضع اسم البرنامج في رسالة الخطأ كي أوضِّح من أين تأتي رسالة الخطأ؛ وذلك مهمٌ خصوصًا في السكربتات الكبيرة والمعقدة التي تُستدعى فيها سكربتات داخل سكربتات… لاحظ أيضًا تضمين متغير البيئة LINENO الذي سيساعد في تحديد السطر الذي حدثت فيه المشكلة. #!/bin/bash # A slicker error handling routine # I put a variable in my scripts named PROGNAME which # holds the name of the program being run. You can get this # value from the first item on the command line ($0). PROGNAME=$(basename $0) error_exit() { # ---------------------------------------------------------------- # Function for exit due to fatal program error # Accepts 1 argument: # string containing descriptive error message # ---------------------------------------------------------------- echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 exit 1 } # Example call of the error_exit function. Note the inclusion # of the LINENO environment variable. It contains the current # line number. echo "Example of error with line number and message" error_exit "$LINENO: An error has occurred." استخدام الحاضنات ({}) داخل الدالة error_exit هو مثالٌ عن "توسعة المعاملات" (parameter expansion)، يمكنك وضع حاضنات حول اسم المتغير (كما في {‎${PROGNAME) إذا أردت عزل المتغير عمّا حوله من نصوص. يُفضِّل البعض وضع الحاضنات حول كل متغير، وهذا الأمر منوطٌ بك. الشيء الآخر الذي أريد الإشارة إليه هو {"‎${1:- "Unknown Error الذي يعني أنَّه لو لم يكن المعامل 1 (أي ‎$1) مُعرَّفًا، فضع السلسلة النصية "Unknown Error" مكانه. يمكن إجراء الكثير من عمليات معالجة النصوص باستخدام توسعة المعاملات. الإشارات Signals لا تستطيع اعتبار أنَّ الأخطاء هي المُسبِّب الوحيد لإنهاء البرنامج على نحوٍ غير متوقع، فعليك أن تحتاط من الإشارات (signals) أيضًا. ليكن لديك المثال الآتي: #!/bin/bash echo "this script will endlessly loop until you stop it" while true; do : # Do nothing done بعد أن تُشغِّل هذا السكربت، فسيبدو وكأنَّه علّق، لكنه -مثل أغلبية البرامج التي تُعلِّق- قد دخل في حلقة تكرار ولم يخرج منها. فالسكربت في مثالنا ينتظر أن يُعيد الأمر true حالة خروج لا تساوي الصفر، وهذا لن يحدث أبدًا. وسيستمر تنفيذ السكربت إلى أن تُرسِل الصَدَفة bash إشارةً له لإيقافه. يمكنك إرسال إشارة بالضغط على Ctrl+c التي تُسمى SIGINT (مختصرة من SIGnal INTerrupt). إنهاء البرامج التي تستقبل إشارات بشكل سليم حسنًا، يمكن أن تأتي إشارة وتؤدي إلى إنهاء تنفيذ السكربت، لكن لماذا نهتم بذلك؟ لا يؤدي إنهاء السكربت عبر الإشارات في العديد من الحالات إلى مشاكل، لكنها تحتاج إلى معالجة في بعض الحالات. لننظر إلى مثالٍ آخر: #!/bin/bash # Program to print a text file with headers and footers TEMP_FILE=/tmp/printfile.txt pr $1 > $TEMP_FILE echo -n "Print file? [y/n]: " read if [ "$REPLY" = "y" ]; then lpr $TEMP_FILE fi يُعالِج السكربت السابق ملفًا نصيًا مُمَرَّرًا كوسيط في سطر الأوامر عبر الأمر pr الذي يُخزِّن الناتج في ملف مؤقت (temporary file)، ثم سيسأل المستخدم عمّا إذا كان يريد طباعة الملف، فلو وافق المستخدم عبر كتابة y فسيُمرَّر الملف المؤقت إلى الأمر lpr للطباعة (يمكنك وضع الأمر less بدلًا من lpr إذا لم تكن لديك طابعة موصولة بحاسوبك). عليّ أن أعترف لك أنَّ السكربت السابق فيه العديد من المشاكل التصميمية؛ وعلى الرغم من استخدامه لاسم الملف المُمرَّر عبر سطر الأوامر، لكنه لا يتحقق أنَّ القيمة فارغة، ولا يتحقق إن كان الملف موجودًا فعلًا. لكن الفكرة التي أريد التركيز عليها هي أنَّه عندما ينتهي تنفيذ السكربت، فسيُبقي خلفه ملفًا مؤقتًا. من المستحسن أن نحذف الملف المؤقت ‎$TEMP_FILE عند انتهاء تنفيذ السكربت، ويتم هذا بسهولة بإضافة السطر الآتي في نهاية السكربت: rm $TEMP_FILE قد تظن أننا حللنا المشكلة، لكن ماذا سيحدث لو ضغط المستخدم على Ctrl+c عندما تظهر الرسالة "Print file? [y/n]:‎" سينتهي تنفيذ السكربت عند الأمر read ولن يُنفَّذ الأمر rm أبدًا. سنحتاج إذًا إلى طريقة لمعالجة الإشارات مثل SIGINT عندما يضغط المستخدم على Ctrl+c. لحسن الحظ، توفِّر bash طريقةً لتنفيذ الأوامر فيما إذا استقبِلَت إشارةٌ ما. الأمر trap يسمح لك الأمر trap بتنفيذ أمر عندما يستقبل سكربتك إشارةً. يعمل هذا الأمر كالآتي: trap arg signals حيث signals هي قائمة بالإشارات التي تريد «اعتراضها» أو معالجتها، و arg هو الأمر التي سيُنفَّذ عندما تُستقبَل واحدة من الإشارات المُحدَّدة. يمكننا التعامل مع الإشارات في سكربت الطباعة السابق كما يلي: #!/bin/bash # Program to print a text file with headers and footers TEMP_FILE=/tmp/printfile.txt trap "rm $TEMP_FILE; exit" SIGHUP SIGINT SIGTERM pr $1 > $TEMP_FILE echo -n "Print file? [y/n]: " read if [ "$REPLY" = "y" ]; then lpr $TEMP_FILE fi rm $TEMP_FILE أضفنا الأمر trap الذي سيُنفِّذ الأمر rm $TEMP_FILE إذا استقبل السكربت إحدى الإشارات المذكورة، التي هي أكثر الإشارات التي ستواجهها، لكن هنالك المزيد منها التي تستطيع ذكرها أيضًا. انظر ناتج الأمر trap -l لرؤية القائمة الكاملة. يمكنك أيضًا ذكر الإشارات بأرقامها بدلًا من أسمائها. الإشارة 9 التي لا ترحم! هنالك إشارة لا تستطيع التعامل معها داخل السكربت: إشارة SIGKILL أو الإشارة رقم 9. ستُنهي النواة أيّ عملية تُرسَل لها هذه الإشارة مباشرةً دون العودة إلى البرنامج أو السماح له بإجراء أيّ عملية لمعالجة الإشارة. ولأنه هذه الإشارة تُنهي البرامج التي تُعلِّق أو لا تستجيب، فربما تظن أنَّها أسهل طريقة لإنهاء برنامج ما. وقد ترى الأمر الآتي عندما يأتي ذكر الإشارة SIGKILL: kill -9 وعلى الرغم من أنَّ هذه الإشارة تُتِمُّ عملها بسرعة وسهولة، لكن تذكَّر أنَّ البرنامج لن يستطيع معالجة هذه الإشارة، ولا بأس في ذلك في بعض الحالات؛ لكن قد يُسبِّب مشاكل في بعضها الآخر. حيث تُنشِئ بعض البرامج المعقدة (وحتى بعض البرامج غير المعقدة) ملفات اسمها lock files لمنع تشغيل عدِّة نسخ من نفس البرنامج في نفس الوقت. فعندما تُرسَل إشارة SIGKILL إلى برنامج يستخدم lock files، فلن يكون لديه فرصة لحذف ذاك الملف؛ وسيؤدي وجود ذاك الملف إلى منع تشغيل البرنامج إلى أن يُحذَف يدويًا. استعمل SIGKILL كملاذٍ أخيرٍ لك. دالة clean_up صحيحٌ أنَّ الأمر trap حلّ المشكلة، لكننا لاحظنا بعض المحدوديات؛ خصوصًا أنَّه لا يقبل إلا سلسلةً نصيةً وحيدةً تحتوي الأمر الذي سيُنفَّذ عندما تُستقبَل الإشارة. يمكنك الالتفاف على هذه المحدودية بوضع ; بين عدِّة أوامر، إلا أنَّ هذه الطريقة بشعة المظهر. فمن الأفضل إنشاء دالة ستُستدعى عندما ينتهي تنفيذ السكربت. أُسميّ هذه الدالة عادةً clean_up. #!/bin/bash # Program to print a text file with headers and footers TEMP_FILE=/tmp/printfile.txt clean_up() { # Perform program exit housekeeping rm $TEMP_FILE exit } trap clean_up SIGHUP SIGINT SIGTERM pr $1 > $TEMP_FILE echo -n "Print file? [y/n]: " read if [ "$REPLY" = "y" ]; then lpr $TEMP_FILE fi clean_up يمكن استعمال دالة clean_up في البُنى التي تهتم بمعالجة الأخطاء. فيجب على أيّة حال أن "تُنظِّف" ما خلّفه السكربت بعد انتهائه (لأي سببٍ كان). هذه هي النسخة النهائية من برنامجنا التي حسّنّا فيها معالجة الأخطاء والإشارات: #!/bin/bash # Program to print a text file with headers and footers # Usage: printfile file # Create a temporary file name that gives preference # to the user's local tmp directory and has a name # that is resistant to "temp race attacks" if [ -d "~/tmp" ]; then TEMP_DIR=~/tmp else TEMP_DIR=/tmp fi TEMP_FILE=$TEMP_DIR/printfile.$$.$RANDOM PROGNAME=$(basename $0) usage() { # Display usage message on standard error echo "Usage: $PROGNAME file" 1>&2 } clean_up() { # Perform program exit housekeeping # Optionally accepts an exit status rm -f $TEMP_FILE exit $1 } error_exit() { # Display error message and exit echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2 clean_up 1 } trap clean_up SIGHUP SIGINT SIGTERM if [ $# != "1" ]; then usage error_exit "one file to print must be specified" fi if [ ! -f "$1" ]; then error_exit "file $1 cannot be read" fi pr $1 > $TEMP_FILE || error_exit "cannot format file" echo -n "Print file? [y/n]: " read if [ "$REPLY" = "y" ]; then lpr $TEMP_FILE || error_exit "cannot print file" fi clean_up الطريقة المثالية لإنشاء ملفات مؤقتة هنالك عدِّة إجراءات يمكننا اتخاذها لتأمين الملف المؤقت الذي استخدمه السكربت. من تقاليد نظام يونكس استخدام المجلد ‎/tmp لتخزين الملفات المؤقتة التي تستعملها البرامج. يمكن للجميع الكتابة إلى ذاك المجلد، وقد يُسبِّب ذلك لك بعض المخاوف الأمنية. تجنّب كتابة الملفات في مجلد ‎/tmp إن كان ذلك ممكنًا. التقنية المُستحسنة هي كتابة الملفات إلى مجلد محلي مثل ‎~/tmp (أي مجلد tmp الموجود في مجلد المنزل للمستخدم المُنفِّذ للسكربت)؛ وإن كان لا بُد، فعليك اتخاذ بعض الخطوات للتأكد أن أسماء الملفات المُخزَّنة في مجلد ‎‎/tmp غير متوقعة؛ حيث تسمح أسماء الملفات المتوقعة للمخترقين أن يُنشِئوا وصلات رمزية إلى ملفات أخرى التي يريدون منك أن تكتب فوقها. الاسم الجيد للملف المؤقت هو الاسم الذي يسمح لك بمعرفة مَن الذي كتب الملف، ولكنه ليس متوقعًا بشكلٍ كامل. استخدمنا السطر الآتي في السكربت أعلاه لإنشاء اسم الملف المؤقت ‎$TEMP_FILE: TEMP_FILE=$TEMP_DIR/printfile.$$.$RANDOM سيحتوي المتغير ‎$TEMP_DIR على ‎‎/tmp أو ‎~/tmp اعتمادًا على توفر المجلد ~/tmp، ومن الشائع تضمين اسم البرنامج في اسم الملف، وهذا هو سبب وضعنا للكلمة "printfile". ثم استخدمنا متغير الصَدَفة $$ لتضمين مُعرِّف العملية (PID) الخاص بالبرنامج. وهذا سيُحدِّد تمامًا ما هي العملية المسؤولة عن الملف. وبالطبع لا نستطيع أن نعتبر أنَّ رقم العملية كافٍ لجعل اسم الملف غير متوقع؛ لهذا أضفنا متغير الصَدَفة ‎$RANDOM لتضمين رقم عشوائي في اسم الملف. وبالآلية السابقة، أنشأنا اسمًا لملفٍ مؤقتٍ سهلُ التعرف وغير متوقع. خاتمة حسنًا، لقد أنهينا هذه السلسلة، أرجو أن تكون قد وجدتها مفيدةً ومسلية في آن واحد. وأنصحك بإكمال مسيرتك في سطر الأوامر وسكربتات الصَدَفة بقراءة كتاب سطر أوامر لينُكس لمترجمه عبد اللطيف ايمش. ترجمة -وبتصرّف- للمقالين Errors And Signals And Traps (Oh My!) - Part 1 و Errors And Signals And Traps (Oh, My!) - Part 2 لصاحبهما William Shotts.
  3. تتوفر آلاف الأوامر لمستخدمي سطر أوامر لينُكس، لكن كيف تستطيع تذكرها جميعًا؟ الجواب هو أنَّك لا تحتاج إلى ذلك؛ فالقوة الحقيقية للحاسوب تظهر عندما يقوم بالعمل عوضًا عنك، وذلك باستخدام سكربتات الصدفة (Shell Scripts) لأتمتة المهام. ما هي سكربتات الصدفة؟ بأبسط تعريفٍ لها: سكربت الصّدفة هو ملف يحتوي على سلسلة من الأوامر التي تقرأها الصَدَفة (shell) وتنفِّذ الأوامر التي فيها كما لو أنها أُدخِلَت مباشرةً من سطر الأوامر. الصَدَفة هي برمجية فريدة من نوعها، وذلك لأنها توفر واجهة سطرية (أي من سطر الأوامر) للتعامل مع النظام مع كونها مُفسِّر (interpreter) للسكربتات. وكما سنرى لاحقًا، أيّ شيء يمكنك القيام به في سطر الأوامر يمكن فعله في سكربتات الصدفة، وأغلبية الأشياء التي تستطيع كتابتها في سكربتات الصدفة يمكن تنفيذها مباشرةً في سطر الأوامر. سنُركِّز في هذه السلسلة على الميزات التي تُستخدم عادةً عند كتابة السكربتات. كتابة أول سكربت لك يجب أن تفعل ثلاثة أشياء لكي تكتب سكربت شِل: كتابة السكربت السماح للصَدَفة (shell) بتنفيذه (أي إعطاؤه إذن التنفيذ x) وضعه في مكانٍ تستطيع الصَدَفة العثور عليه فيه سكربت الصّدفة ما هو إلا ملف يحتوي على نص عادي؛ فلا يلزمك إلا محرر نصي لكتابة سكربتات الصدفة. "المحرر النصي" هو برنامج -يشبه برامج التحرير المكتبي- يستطيع قراءة وكتابة ملفات ASCII النصية. هنالك الكثير من المحررات النصية المتوفرة على نظام لينُكس سواءً كانت سطريةً (أي تعمل من سطر الأوامر) أم رسوميةً؛ هذه قائمة تحتوي على أشهرها: vi أو vim: المحرر النصي السطري الشهير في نظام يونكس المعروف بصعوبة فهم بنية الأوامر فيه؛ لكنه -على الكفة الأخرى- محرر كفؤ وقوي جدًا وخفيف وسريع. سيؤتي تعلم vi أُكله لأنه متوفر على جميع الأنظمة الشبيهة بِيونكس (Unix-like). النسخة الموجودة من vi في أغلبية توزيعات لينُكس هي النسخة المُحسَّنة التي تدعى vim. Emacs: كبير المحررين في عالم النصوص الذي برمَجَه ريتشارد ستالمان. يحتوي محرر Emac (أو يستطيع أن يحتوي) على كل ميزة يمكن أن تتواجد في أي محرر نصي على الإطلاق! يجدر بالذكر أنَّ مستخدمي vi و Emacs يشتبكون مع بعضهم (على الإنترنت بالطبع!) محاولين إثبات أنَّ محررهم هو الأفضل. nano: هو برنامج سطري شبيه بالمحرر النصي المضمَّن مع عميل البريد الإلكتروني pine، وهو سهل الاستخدام لكن ميزاته قليلة. أنصح عادةً باستخدام nano لمَن يتعامل مع سطر الأوامر لأول مرة. gedit: هو محرر رسومي يأتي مع سطح مكتب غنوم (Gnome). kate: هو محرر رسومي ذو ميزات متقدمة تُسهِّل كتابة السكربتات ويأتي مع حزمة برمجيات كدي (KDE). افتح الآن محررك النصي المفضَّل واكتب فيه أول سكربت لك: !/bin/bash My first script echo "Hello World!" إذا كنتَ سريع البديهة، فمن المرجح أنَّك عرفت كيف تلصق النصوص في المحرر النصي الذي اخترته. إذا فتحت أيّ كتابٍ عن البرمجة من قبل، فستتعرف مباشرةً على برنامج "Hello World" التقليدي الذي يُجسِّده المثال السابق. احفظ الملف باسمٍ ذي معنى (ربما hello_world). أول سطر في الملف مهمٌ وله تأثيرٌ خاص، إذ يُسمى "shebang" وسيخبر الصَدَفة أيّ مُفسِّر عليها استدعاؤه لتفسير هذا السكربت، الذي هو في حالتنا ‎/bin/bash. تستعمل لغات السكربتات الأخرى مثل perl و awk و tcl و php و python هذه الآلية. السطر الثاني في الملف هو تعليق. أيّ شيء يأتي بعد علامة يُعتبر تعليقًا وستتجاهله الصَدَفة تمامًا. لكن عندما يزداد تعقيد برامجك فستصبح التعليقات مهمة جدًا، إذ يستعملها المبرمجون لشرح ما حولها لتسهيل فهم الآخرين له. آخر سطر في السكربت السابق هو الأمر echo الذي يطبع ما يليه على الشاشة. ضبط الأذونات علينا الآن إعطاء إذن التنفيذ لسكربت الصّدفة الذي كتبناه، وذلك بالأمر chmod كما يلي: $ chmod 755 hello_world الإذن "755" سيسمح لك بالقراءة والكتابة والتنفيذ، بينما سيتمكن بقية المستخدمين من قراءة وتنفيذ السكربت فقط. أما إذا أردت أن يكون السكربت خاصًا بك (أي أنَّك الوحيد الذي تستطيع قراءته وتنفيذه) فضع "700" بدلًا من "755". راجع درس مبادئ أذونات الملفات على لينكس للمزيد من المعلومات. وضع الملف في المكان الصحيح تستطيع عند هذه المرحلة تشغيل السكربت كما يلي: $ ./hello_world يجب أن تشاهد العبارة "Hello World!‎" على الشاشة، وإن لم ترها فانظر أين حفظت السكربت، وانتقل إلى ذاك المجلد (بالأمر cd) ثم جرب مرِّة أخرى. علينا الآن أن نتوقف قليلًا ونتحدث عن المسارات. عندما تكتب اسم أحد الأوامر فلن يبحث النظام (أو بالأحرى "الصَدَفة") عن ذاك البرنامج في جميع مجلدات حاسوبك لأن ذلك سيستغرق وقتًا طويلًا؛ ولكنك لاحظت أيضًا كيف أنَّك لا تحتاج إلى تحديد المسار الكامل للبرامج التي تريد تشغيلها وستظن أنَّ الصَدَفة تعرف أين تجدها. حسنًا، أنت محق: الصَدَفة تعرف أين تجد البرمجيات، لأنها -أي الصَدَفة- تحتوي على قائمة بالمجلدات التي تتواجد فيها الملفات التنفيذية (أي البرامج)، وستبحث داخل المجلدات في تلك القائمة عن البرامج، فإن لم تجد ما تبحث عنه في أحد تلك المجلدات فستظهر رسالة الخطأ الشهيرة command not found. يمكنك أن ترى تلك القائمة بكتابة الأمر الآتي: $ echo $PATH الذي سيطبع قائمة مفصولة بنقطتين رأسيتين للمجلدات التي سيتم البحث فيها عن البرامج إذا لم يُحدَّد مسارها الكامل. لاحظ كيف أننا حدَّدنا المسار (‎./‎) عند محاولتنا تشغيل السكربت سابقًا. يمكنك إضافة مجلدات إلى تلك القائمة باستخدام الأمر الآتي، حيث directory هو مسار المجلد الذي تريد إضافته: $ export PATH=$PATH:directory لكن من المستحسن أن تُعدِّل ملف ‎.bashrc‎ أو ‎.profile (اعتمادًا على توزيعتك) لتضمين الأمر السابق فيه، وبهذا سيُنفَّذ في كل مرّة تُسجِّل دخولك فيها. تسمح بعض توزيعات لينُكس بإنشاء مجلد خاص بكل مستخدم ليضع فيه برامجه الشخصية، ويدعى ذاك المجلد bin وهو مجلد فرعي موجود في مجلد المنزل (home) الخاص بك. إن لم يكن موجودًا، فتستطيع إنشاءه بالأمر: $ mkdir bin انقل السكربت إلى مجلد bin (ربما تستخدم الأمر mv) ثم اكتب: $ hello_world وسيعمل السكربت. لاحظ أنَّك قد تحتاج في بعض التوزيعات (مثل أوبنتو) إلى بدء جلسة (session) جديدة حتى تتعرَّف الصَدَفة على المجلد bin. ترجمة -وبتصرّف- للمقال Writing Your First Script And Getting It To Work لصاحبه William Shotts.
  4. بعد أن تعلمنا التعامل مع المعاملات الموضعية (Positional parameters) في الدرس السابق، حان الوقت الآن لشرح آخر بُنية من بُنى التحكم: for. وكما في البنيتين while و until، تُستعمَل for لإنشاء حلقات تكرار. الشكل العام لحلقة for: for variable in words; do commands done الخلاصة هي أنَّ for تُسنِد كلمةً من قائمة الكلمات إلى متغيّرٍ معيّن، ثم تُنفِّذ الأوامر الموجودة داخل الحلقة، ثم تكرر ذلك إلى أن تُستعمَل جميع الكلمات الموجودة في القائمة. هذا مثالٌ عنها: #!/bin/bash for i in word1 word2 word3; do echo $i done أُسنِدَت -في بادئ الأمر- القيمة word1 إلى المتغير i، ثم نُفِّذ الأمر echo $i، ثم أُسنِدَت القيمة word2 إلى المتغير i، ثم نُفِّذ الأمر echo $i، وهكذا، إلى أن تُسنَد جميع الكلمات إلى المتغير i. الشيء المثير للاهتمام في for هو تنوع الطرائق التي تستطيع فيها بناء قائمة الكلمات، حيث يمكن استخدام جميع أنواع التوسعات (expansions). سنولِّد قائمة الكلمات في المثال الآتي باستخدام تعويض الأوامر (command substitution): #!/bin/bash count=0 for i in $(cat ~/.bash_profile); do count=$((count + 1)) echo "Word $count ($i) contains $(echo -n $i | wc -c) characters" done قمنا في المثال السابق بإحصاء عدد الكلمات في ملف ‎.bash_profile، ثم أظهرنا عدد الحروف في كل كلمة. حسنًا، ما علاقة ذلك بالمعاملات الموضعية؟ حسنًا، يمكن استخدام المعاملات الموضعية كقائمة بالكلمات التي ستمرّ عليها الحلقة for: #!/bin/bash for i in "$@"; do echo $i done المتغير "@" هو متغيرٌ خاصٌ بالصَدَفة ويحتوي على قائمة بوسائط سطر الأوامر. تُستعمَل هذه التقنية عادةً لمعالجة قائمة ملفات عبر سطر الأوامر. هذا مثالٌ آخر: #!/bin/bash for filename in "$@"; do result= if [ -f "$filename" ]; then result="$filename is a regular file" else if [ -d "$filename" ]; then result="$filename is a directory" fi fi if [ -w "$filename" ]; then result="$result and it is writable" else result="$result and it is not writable" fi echo "$result" done جرِّب السكربت السابق، ومرِّر إليه قائمةً بعدِّة ملفات، أو استعمل محرفًا بديلًا مثل * وانظر إلى مخرجاته. هذا سكربتٌ آخر يُقارِن الملفات الموجودة في مجلدين، ويظهِر قائمة بالملفات الموجودة في المجلد الأول وغير الموجودة في المجلد الثاني: #!/bin/bash # cmp_dir - program to compare two directories # Check for required arguments if [ $# -ne 2 ]; then echo "usage: $0 directory_1 directory_2" 1>&2 exit 1 fi # Make sure both arguments are directories if [ ! -d $1 ]; then echo "$1 is not a directory!" 1>&2 exit 1 fi if [ ! -d $2 ]; then echo "$2 is not a directory!" 1>&2 exit 1 fi # Process each file in directory_1, comparing it to directory_2 missing=0 for filename in $1/*; do fn=$(basename "$filename") if [ -f "$filename" ]; then if [ ! -f "$2/$fn" ]; then echo "$fn is missing from $2" missing=$((missing + 1)) fi fi done echo "$missing files missing" لنوظِّف ما سبق في مثالٌ عملي. لنحاول تحسين الدالة home_space في السكربت الذي نبنيه لكي تُخرِج المزيد من المعلومات. كانت النسخة القديمة من الدالة تبدو كما يلي: home_space() { # Only the superuser can get this information if [ "$(id -u)" = "0" ]; then echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" fi } # end of home_space هذه هي النسخة الحديثة منها: home_space() { echo "<h2>Home directory space by user</h2>" echo "<pre>" format="%8s%10s%10s %-s\n" printf "$format" "Dirs" "Files" "Blocks" "Directory" printf "$format" "----" "-----" "------" "---------" if [ $(id -u) = "0" ]; then dir_list="/home/*" else dir_list=$HOME fi for home_dir in $dir_list; do total_dirs=$(find $home_dir -type d | wc -l) total_files=$(find $home_dir -type f | wc -l) total_blocks=$(du -s $home_dir) printf "$format" $total_dirs $total_files $total_blocks done echo "</pre>" } # end of home_space تتضمن هذه النسخة المُحسَّنة أمرًا جديدًا هو printf، الذي يُستخدم لتنسيق المُخرجات بناءً على محتويات "عبارة التنسيق" (format string). تنحدر أصول الأمر printf من لغة البرمجة C وهو موجودٌ أيضًا في لغاتٍ برمجيةٍ أخرى مثل C++‎ و Perl و awk و java و PHP وبالطبع bash. هنالك أمرٌ آخر جديد هو الأمر find، الذي يُستخدم للبحث عن ملفات أو مجلدات تُطابِق معيارًا أو مقياسًا محدَّدًا (criteria). استخدمنا الأمر find في الدالة home_space لعرض قائمة بالمجلدات والملفات العادية الموجودة في مجلد المنزل، ثم أحصينا عدد الملفات والمجلدات باستخدام الأمر wc (تذكَّر أنَّه اختصار للعبارة "Word Count"). النقطة المثيرة للاهتمام في دالة home_space المُعدَّلة هي كيفية تعاملنا مع مشكلة عدم السماح بالوصول إلى مجلدات المنزل من المستخدمين العاديين، يمكنك ملاحظة أنَّنا اختبرنا إن كان المستخدم هو الجذر بوساطة id ثم -اعتمادًا على ناتج الاختبار- أسندنا سلاسل نصية مختلفة إلى المتغير dir_list، الذي سيُمثِّل قائمة الكلمات لحلقة for التي تليه. وبهذه الطريقة، إذا شغَّل مستخدمُ عاديٌ السكربت، فستُعرض معلومات عن مجلد المنزل الخاص به فقط. موضوعٌ آخر يمكننا توظيف حلقة for فيه هو الدالة system_info التي لم نكملها بعد. يمكننا كتابتها كالآتي: system_info() { # Find any release files in /etc if ls /etc/*release 1>/dev/null 2>&1; then echo "<h2>System release info</h2>" echo "<pre>" for i in /etc/*release; do # Since we can't be sure of the # length of the file, only # display the first line. head -n 1 $i done uname -orp echo "</pre>" fi } # end of system_info حدَّدنا في بادئ الأمر إن كانت هنالك ملفات release لكي نعالجها. تحتوي ملفات release على اسم التوزيعة وإصدارها. وهي موجودة في مجلد ‎/etc. ولكي نكتشف وجودها، سنستعمل الأمر ls لكننا لسنا مهتمين بمخرجات الأمر، وإنما بحالة الخروج، التي ستكون مساوية للصفر (true) إن وُجِدَت أيّة ملفات. الخطوة الآتية هي طباعة شيفرة HTML لهذا القسم من الصفحة؛ ولمّا كنا نعلم أنَّ هنالك عدِّة ملفات release لكي نعالجها، فسنستخدم حلقة for للمرور على كلٍ واحدٍ منها. ثم سنستعمل الأمر head في داخل الحلقة للحصول على السطر الأول من كل ملف. في النهاية، استعملنا الأمر uname مع الخيارات o و r و p للحصول على بعض المعلومات الإضافية حول النظام. ترجمة -وبتصرّف- للمقال Flow Control - Part 3 لصاحبه William Shotts.
  5. لدينا السكربت التالي: #!/bin/bash # sysinfo_page - A script to produce a system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { echo "<h2>System release info</h2>" echo "<p>Function not yet implemented</p>" } # end of system_info show_uptime() { echo "<h2>System uptime</h2>" echo "<pre>" uptime echo "</pre>" } # end of show_uptime drive_space() { echo "<h2>Filesystem space</h2>" echo "<pre>" df echo "</pre>" } # end of drive_space home_space() { # Only the superuser can get this information if [ "$(id -u)" = "0" ]; then echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" fi } # end of home_space ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ تعمل أغلبية الميزات التي فيه عملًا سليمًا، لكن هنالك بعض الميزات التي أرغب بإضافتها: أريد تحديد اسم ملف الخرج في سطر الأوامر، بالإضافة إلى ضبط اسم ملف افتراضي إن لم يُحدِّد المستخدم اسم الملف. أريد توفير نمط تفاعلي يسأل المستخدم عن اسم الملف ويُحذِّر المستخدم إن كان الملف موجودًا ويسأله إذا كان يريد إعادة الكتابة فوقه. من البديهي توفر خيار للمساعدة يعرض رسالة توضِّح كيفية الاستخدام. تتطلب جميع الميزات السابقة استخدام الخيارات والوسائط في سطر الأوامر، وتوفِّر لنا الصَدَفة المعاملات الموضعية (positional parameters) للوصول إليها. المعاملات الموضعية هي سلسلة من المتغيرات (من ‎$0‎ إلى ‎$9) التي تحتوي على قيم الوسائط في سطر الأوامر. لنتخيل تنفيذ الأمر الآتي: $ some_program word1 word2 word3 إذا كان some_program سكربت صَدَفة، فسيستطيع قراءة كل عنصر من عناصر السطر السابق لأنَّ المعاملات الموضعية تحتوي على ما يلي: سيحتوي المتغير ‎$0 على "some_program" سيحتوي المتغير ‎$1 على "word1" سيحتوي المتغير ‎$2 على "word2" سيحتوي المتغير ‎$3 على "word3 هذا هو السكربت الذي تستطيع تجربته لتشاهد ما سبق عمليًا: #!/bin/bash echo "Positional Parameters" echo '$0 = ' $0 echo '$1 = ' $1 echo '$2 = ' $2 echo '$3 = ' $3 اكتشاف وجود وسائط في سطر الأوامر عليك عادةً التحقق من وجود وسائط لكي يتصرَّف برنامجك وفقها؛ وهنالك طريقتان لفعل ذلك. أولهما هي التحقق من احتواء المتغير ‎$1 لأي قيمة كما يلي: #!/bin/bash if [ "$1" != "" ]; then echo "Positional parameter 1 contains something" else echo "Positional parameter 1 is empty" fi تحتوي الصَدَفة على متغير اسمه ‎$#‎ الذي يحتوي على عدد الوسائط في سطر الأوامر، وهذه هي الطريقة الثانية. #!/bin/bash if [ $# -gt 0 ]; then echo "Your command line contains $# arguments" else echo "Your command line contains no arguments" fi خيارات سطر الأوامر العديد من البرامج، وخصوصًا تلك التي أتت من مشروع GNU، تدعم خيارات طويلة ومختصرة لسطر الأوامر. فمثلًا، ستستعمل الخيار المختصر ‎-h لعرض رسالة المساعدة لأغلبية البرامج أو الخيار الطويل ‎--help. تُسبَق أسماء الخيارات الطويلة عادةً بشرطتَين (--). سنستعمل هذا العرف في سكربتاتنا. interactive= filename=~/sysinfo_page.html while [ "$1" != "" ]; do case $1 in -f | --file ) shift filename=$1 ;; -i | --interactive ) interactive=1 ;; -h | --help ) usage exit ;; * ) usage exit 1 esac shift done الشيفرة السابقة معقدة بعض الشيء، تحملني قليلًا ريثما أشرحها لك. السطران الأولان سهلان، لم نضبط قيمةً للمتغير interactive، مما يُشير إلى أنَّ المستخدم لم يطلب الوضع التفاعلي، ثم ضبطنا المتغير filename إلى قيمة افتراضية، حيث سيُستخدَم هذا الاسم إن لم يُحدَّد اسمٌ آخر في سطر الأوامر. أصبح لدينا الآن قيمٌ افتراضية في حال لم يضع المستخدم أيّة خيارات في سطر الأوامر. أنشأنا بعد ذلك حلقة while التي تمر على جميع عناصر سطر الأوامر وتتحقق من قيمها عبر كتلة case، التي تكتشف وضع كل خيار من الخيارات الممكنة وتتعامل معه كما يجب. الجزء المهم في السكربت السابق هو آلية عمل حلقة التكرار. تعتمد الحلقة السابقة على الأمر shift. الأمر shift هو أمرٌ مضمَّن في الصَدَفة ويتعامل مع المعاملات الموضعية، حيث يؤدي إلى "إزاحة" أرقام جميع المعاملات وذلك بإنقاص 1 منها وذلك في كل مرة يُستدعى فيها. سيصبح ‎$2 -على سبيل المثال- ‎$1، و ‎$3 سيصبح ‎$2، و ‎ $4سيصبح ‎$3، وهكذا. جرِّب السكربت الآتي: #!/bin/bash echo "You start with $# positional parameters" # Loop until all parameters are used up while [ "$1" != "" ]; do echo "Parameter 1 equals $1" echo "You now have $# positional parameters" # Shift all the parameters down by one shift done الحصول على وسيط أحد الخيارات يتطلب الخيار ‎-f ذكر اسم الملف الذي ستُحفَظ فيه المخرجات بعده. يمكننا استخدام shift مرةً أخرى للحصول على اسم العنصر التالي من وسائط سطر الأوامر وإسناد قيمته إلى المتغير filename. سنتحقق لاحقًا من قيمة filename للتأكد أنَّها تُمثِّل اسم ملف صحيح. دمج مفسر خيارات سطر الأوامر مع السكربت علينا الآن نقل بعض الأقسام من مكانها، وإضافة دالة لعرض طريقة استخدام الخيارات التي أضفناها أخيرًا إلى السكربت، وسنضيف اختبارًا للتأكد من صحة تفسير خيارات سطر الأوامر. سيبدو السكربت بعد التعديل كالآتي: #!/bin/bash # sysinfo_page - A script to produce a system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { echo "<h2>System release info</h2>" echo "<p>Function not yet implemented</p>" } # end of system_info show_uptime() { echo "<h2>System uptime</h2>" echo "<pre>" uptime echo "</pre>" } # end of show_uptime drive_space() { echo "<h2>Filesystem space</h2>" echo "<pre>" df echo "</pre>" } # end of drive_space home_space() { # Only the superuser can get this information if [ "$(id -u)" = "0" ]; then echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" fi } # end of home_space write_page() { cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ } usage() { echo "usage: sysinfo_page [[[-f file ] [-i]] | [-h]]" } ##### Main interactive= filename=~/sysinfo_page.html while [ "$1" != "" ]; do case $1 in -f | --file ) shift filename=$1 ;; -i | --interactive ) interactive=1 ;; -h | --help ) usage exit ;; * ) usage exit 1 esac shift done # Test code to verify command line processing if [ "$interactive" = "1" ]; then echo "interactive is on" else echo "interactive is off" fi echo "output file = $filename" # Write page (comment out until testing is complete) # write_page > $filename إضافة النمط التفاعلي يمكن إضافة النمط التفاعلي بهذه الشيفرة: if [ "$interactive" = "1" ]; then response= echo -n "Enter name of output file [$filename] > " read response if [ -n "$response" ]; then filename=$response fi if [ -f $filename ]; then echo -n "Output file exists. Overwrite? (y/n) > " read response if [ "$response" != "y" ]; then echo "Exiting program." exit 1 fi fi fi تحققنا أولًا من أنَّ النمط التفاعلي مُفعَّل، وإلا فلا حاجة إلى فعل شيء. ثم سألنا المستخدم عن اسم الملف؛ لاحظ طريقة صياغة السؤال: echo -n "Enter name of output file [$filename] > " سنعرض القيمة الحالية للمتغير filename، لأنَّه لو ضغط المستخدم على زر Enter دون كتابة أيّ شيء، فستُستخدم القيمة الافتراضية للمتغير filename؛ ويتم ذلك عبر السطرين اللذان يليانه، حيث يتحققا من قيمة response؛ فإن لم تكن قيمة response فارغةً، فستُسنَد قيمة response إلى المتغير filename. وإلا فستُترَك قيمة filename على حالها، محتفظةً بقيمتها الافتراضية. بعد أن يُدخِل المستخدم اسم ملف الخرج، فسنتحقق من أنَّه موجود، فإن كان موجودًا، فسنسأل المستخدم إن كان يريد استبداله، وإن لم يكن جواب المستخدمy، فسينتهي تنفيذ البرنامج دون كتابة الملف. ترجمة -وبتصرّف- للمقال Positional Parameters لصاحبه William Shotts.
  6. تعلمنا في الجزء الأول من بُنى التحكم عن الأمر if وكيف يُستخدم لتعديل مسار تنفيذ البرنامج بناءً على حالة خروج أحد الأوامر. يسمى هذا النوع من مسارات تنفيذ البرامج -وفق الاصطلاحات البرمجية- بالتفرّع (branching) لأنَّه يشبه كثيرًا التنقل في شجرة، فعندما تصل إلى تفرّع، فستُحدِّد نتيجة الشرط أيَّ فرعٍ ستذهب إليه. هنالك نوعٌ آخرٌ أكثر تعقيدًا من أنواع التفرع يُسمى case، وهنالك عدِّة خيارات في case، فعلى عكس التفرّع البسيط الذي فيه طريقان فقط، يمكن أن تكون هنالك عدِّة نواتج بناءً على تحقيق شرط معيّن لقيمةٍ ما. يمكنك بناء مثل هذا النوع من أنواع التفرّع باستخدام عدِّة جمل if شرطية. سنحاول في المثال الآتي التحقق من مدخلات المستخدم: #!/bin/bash echo -n "Enter a number between 1 and 3 inclusive > " read character if [ "$character" = "1" ]; then echo "You entered one." elif [ "$character" = "2" ]; then echo "You entered two." elif [ "$character" = "3" ]; then echo "You entered three." else echo "You did not enter a number between 1 and 3." fi لكن ما سبق ليس كفؤًا كما كنا نتوقع، ولكن لحسن الحظ، توفِّر الصَدَفة لنا حلًا أفضل لهذه المشكلة: الأمر المُضمَّن ‏case، الذي يمكن استخدامه لبناء برنامج مكافئ تمامًا للبرنامج السابق: #!/bin/bash echo -n "Enter a number between 1 and 3 inclusive > " read character case $character in 1 ) echo "You entered one." ;; 2 ) echo "You entered two." ;; 3 ) echo "You entered three." ;; * ) echo "You did not enter a number between 1 and 3." esac الشكل العام للأمر case: case word in patterns ) commands ;; esac يُنفِّذ الأمر case عباراتٍ برمجيةً معيّنة إذا طابَقت الكلمة نمطًا (pattern)، يمكنك وضع أي عدد من الأنماط والعبارات. ويمكن أن تكون الأنماط نصًا عاديًا أو "محارف بديلة" (wildcards). يمكن وضع أكثر من نمط في نفس السطر بفصل الأنماط بمحرف |. هذا مثالٌ متقدمٌ يشرح لك ما أعنيه بكلامي السابق: #!/bin/bash echo -n "Type a digit or a letter > " read character case $character in # Check for letters [[:lower:]] | [[:upper:]] ) echo "You typed the letter $character" ;; # Check for digits [0-9] ) echo "You typed the digit $character" ;; # Check for anything else * ) echo "You did not type a letter or a digit" esac لاحظ النمط الخاص * الذي سيُطابِق أي شيء، لذلك سنحتاج إليه لمطابقة الحالات التي لم تُطابِقها الأنماط التي تسبقه. من المستحسن تضمين هذا النمط في نهاية الأمر case لكي يُستخدَم لكشف المدخلات غير الصحيحة. حلقات التكرار آخر جزء من بُنى التحكم التي سنناقشها هي حلقات التكرار، تُنفِّذ حلقات التكرار قسمًا من البرنامج لعددٍ من المرات وذلك بناءً على حالة خروج أحد الأوامر. توفِّر الصَدَفة ثلاثة أوامر للتكرار: while و until و for، وسنشرح while و until في هذا الدرس وسنترك for لدرسٍ لاحق. يؤدي الأمر while إلى تنفيذ كتلة من الشيفرة مرارًا وتكرارًا لطالما كانت حالة خروج الأمر المُحدَّد true (أي حالة الخروج 0). هذا مثالٌ بسيطٌ يعد الأرقام من 0 إلى 9: #!/bin/bash number=0 while [ "$number" -lt 10 ]; do echo "Number = $number" number=$((number + 1)) done أنشأنا في السطر الثالث متغيرًا وأسميناه number وأسندنا القيمة 0 إليه، ثم بدأنا حلقة while. وكما لاحظت، كان الأمر التي ستختبر حلقة while حالة خروجه هو الأمر test الذي يختبر قيمة العدد number. وفي مثالنا السابق، اختبرنا إذا كانت قيمة number أصغر من 10. لاحظ الكلمة do في السطر الرابع والكلمة done في السطر السابق. هاتان الكلمتان تحيطان بالشيفرة التي ستُكرَّر لطالما كانت حالة خروج الأمر المُحدَّد مساويةً للصفر. في غالبية الحالات، تقوم الشيفرة التي ستُكرَّر بشيءٍ ما سيؤدي في نهاية المطاف إلى تغيير حالة خروج الأمر المُحدَّد، وإلا فستكون لديك حلقة تكرار لا نهائية؛ أي حلقةُ تكرارٍ لا يتوقف تنفيذها أبدًا. تطبع الشيفرة التي ستُكرَّر في المثال السابق قيمة المتغير number (الأمر echo في السطر الخامس)، ثم تُزيد قيمة number بمقدار 1 في السطر السادس. وفي كل مرة يكتمل فيها تنفيذ الشيفرة، فسيتم التحقق من قيمة حالة الخروج للأمر test، وبعد التكرار العاشر للحلقة، فسيزداد المتغير number عشر مرات وسينتهي الأمر test بحالة خروج لا تساوي الصفر. وفي هذه المرحلة، سيُكمِل البرنامج مساره بتنفيذ التعليمات البرمجية التي تلي الكلمة done، لكن ولمّا كانت done هي آخر كلمة في مثالنا، فسينتهي تنفيذ البرنامج فورًا. يعمل الأمر until بشكلٍ مماثل، عدا أنَّ الشيفرة ستُكرَّر لطالما كانت حالة خروج الأمر المُحدَّد false (أي ليست 0). لاحظ تغيير التعبير الذي مررناه للأمر test لكي يعمل بشكلٍ مماثل للمثال السابق عن حلقة while: #!/bin/bash number=0 until [ "$number" -ge 10 ]; do echo "Number = $number" number=$((number + 1)) done بناء قائمة طريقة شائعة لتوفير واجهة للمستخدم للبرامج النصيّة (أي التي تعمل من سطر الأوامر) هي استخدام القوائم. القائمة هي سلسلة من الخيارات التي يستطيع المستخدم انتقاء واحدة منها. سنستخدم ما تعلمناه سابقًا عن الحلقات وعبارة case لبناء برنامج بسيط فيه قائمة: #!/bin/bash selection= until [ "$selection" = "0" ]; do echo " PROGRAM MENU 1 - Display free disk space 2 - Display free memory 0 - exit program " echo -n "Enter selection: " read selection echo "" case $selection in 1 ) df ;; 2 ) free ;; 0 ) exit ;; * ) echo "Please enter 1, 2, or 0" esac done الغرض من حلقة until هو إعادة عرض القائمة في كل مرة يتم اختيار عنصر من القائمة فيها. ستتكرر الحلقة إلى أن يختار المستخدم 0 (خيار الخروج). لاحظ ماذا سنفعل إذا لم تكن مدخلات المستخدم صحيحة (1 أو 2 أو 0). نستطيع إضافة دالة تطلب من المستخدم الضغط على الزر Enter بعد عرض كل خيار لتحسين طريقة عرض البرنامج عند تشغيله، وذلك بمسح الشاشة قبل إعادة عرض القائمة مرةً أخرى. هذا هو المثال المُحسَّن: #!/bin/bash press_enter() { echo -en "\nPress Enter to continue" read clear } selection= until [ "$selection" = "0" ]; do echo " PROGRAM MENU 1 - display free disk space 2 - display free memory 0 - exit program " echo -n "Enter selection: " read selection echo "" case $selection in 1 ) df ; press_enter ;; 2 ) free ; press_enter ;; 0 ) exit ;; * ) echo "Please enter 1, 2, or 0"; press_enter esac done عندما "يُعلِّق" حاسوبك … لقد مررنا جميعًا بتجربة "تعليق" أحد البرامج، الذي يحدث عندما يتوقف البرنامج عن العمل ولا يستجيب لأي شيء. ربما تظن أنَّ البرنامج قد توقف، إلا أنَّه -في معظم الحالات- ما يزال يعمل لكن واجهته مشكلةٌ في البنية المنطقية فيه وقد دخل في حلقة تكرار لا نهائية. تخيل هذه الحالة: لنقل أنَّك وصلت جهازًا خارجيًا إلى حاسوبك، مثل قرص USB، لكنك نسيت تشغيله. ثم حاولت استخدام الجهاز لكن التطبيق علّق، فعندما يحدث ذلك، تستطيع أن تتخيل المحادثة الآتية بين التطبيق والمنفذ الذي يتصل عبره الجهاز: وسيستمر الأمر هكذا إلى ما لا نهاية … البرامج المكتوبة بطريقة جيدة تتفادى الحالة السابقة بضبط مهلة زمنية (timeout)، وهذا يعني أنَّ حلقة التكرار تحسب عدد المحاولات أو تحسب مقدار الزمن الذي انتظرته لكي يحدث شيءٌ مُحدَّد. وإن تجاوز عدد المحاولات أو الزمن المُنتَظَر حدًّا معيّنًا، فسينتهي تنفيذ الحلقة وسيولِّد البرنامج رسالة خطأ. ترجمة -وبتصرّف- للمقال Flow Control - Part 2 لصاحبه William Shotts.
  7. لم تكن السكربتات التي نكتبها إلى الآن تفاعليةً، أي أنها لا تتطلب أيّ مدخلاتٍ من المستخدم. سنرى في هذا الدرس كيف نجعل السكربتات تسأل المستخدم أسئلةً وتحصل على الإجابة وتستخدمها. read استعمل الأمر read للحصول على مدخلات من لوحة المفاتيح. يأخذ الأمر read المدخلات من لوحة المفاتيح ويُسنِدها إلى متغير. هذا مثالٌ بسيطٌ عنه: #!/bin/bash echo -n "Enter some text > " read text echo "You entered: $text" عرضنا رسالةً في السطر الثالث، لاحظ كيف استعملنا الخيار ‎-n لكي نجعل الأمر echo يُبقي على مؤشر الكتابة موجودًا في نفس السطر، أي أنَّه لن يطبع محرف الانتقال إلى سطرٍ جديد (كالعادة). ثم استدعينا الأمر read مع تمرير text كوسيط، وما سيفعله هو انتظار المستخدم إلى أن يكتب شيئًا ثم يضغط على زر Enter، ثم سيُسنِد ما كتبه المستخدم إلى المتغير text. هذا مثالٌ جربنا فيه السكربت السابق: $ read_demo.bash Enter some text > this is some text You entered: this is some text إن لم تُحدِّد اسم المتغير الذي تريد أن يحفظ الأمر read مدخلات المستخدم فيه، فسيَستعمِل متغير البيئة REPLY. هنالك عدِّة خيارات للأمر read، أهم اثنين منها هما ‎-t و ‎-s. يأتي الخيار ‎ -tمتبوعًا بعدد الثواني التي سينتظر فيها الأمرُ read المستخدمَ لتوفير مدخلات. وهذا يعني أنَّ الأمر read سيتوقف عن قبول مدخلات من المستخدم بعد هذه المهلة الزمنية. يمكن أن يُستخدَم هذا الخيار إذا كان على السكربت الاستمرار في التنفيذ حتى لو لم يوفِّر المستخدم مدخلات (ربما ستوضع قيمة افتراضية بدلًا من مدخلات المستخدم في هذه الحالة). هذا مثالٌ عن الخيار ‎-t: #!/bin/bash echo -n "Hurry up and type something! > " if read -t 3 response; then echo "Great, you made it in time!" else echo "Sorry, you are too slow!" fi يؤدي الخيار ‎-s إلى عدم إظهار المدخلات التي يكتبها المستخدم على الشاشة، وهذا مفيدٌ عندما تسأل المستخدم عن كلمة مروره، أو غير ذلك من المعلومات السرية. العمليات الحسابية من البديهي أنَّ الحاسوب يستطيع إجراء عمليات حسابية بسيطة. توفِّر الصدفة إمكانية إجراء عمليات حسابية على الأعداد الصحيحة (integer). ما هي الأعداد الصحيحة؟ هي الأعداد الكاملة مثل 1 و 2 و 456 و -235 التي لا تحتوي على فواصل عشرية مثل 0.5 و ‎.443 أو 3.1415. إذا كان من الضروري أن تتعامل مع الأعداد العشرية، فهنالك برنامجٌ منفصل اسمه bc الذي تتعامل معه بلغة خاصة للحساب الدقيق، ويمكن أن يُستعمَل في سكربتات الصَدَفة لكنه خارج عن نطاق هذه السلسلة. لنقل أنَّك تريد استخدام سطر الأوامر كآلة حاسبة بسيطة. تستطيع فعل ذلك كالآتي: $ echo $((2+2)) عندما تواجه الصَدَفة التعبير ‎$(( ))‎ فستحاول وضع ناتج العملية الحسابية الموجودة داخل الأقواس بدلًا منه. لاحظ كيف سيتم تجاهل الفراغات: $ echo $((2+2)) 4 $ echo $(( 2+2 )) 4 $ echo $(( 2 + 2 )) 4 تستطيع الصَدَفة إجراء مختلف العمليات الحسابية الشهيرة (وغير الشهيرة). هذا مثالٌ عنها: #!/bin/bash first_num=0 second_num=0 echo -n "Enter the first number --> " read first_num echo -n "Enter the second number -> " read second_num echo "first number + second number = $((first_num + second_num))" echo "first number - second number = $((first_num - second_num))" echo "first number * second number = $((first_num * second_num))" echo "first number / second number = $((first_num / second_num))" echo "first number % second number = $((first_num % second_num))" echo "first number raised to the" echo "power of the second number = $((first_num ** second_num))" لاحظ أنَّ علامة $ التي تسبق أسماء المتغيرات غير ضرورية داخل التعابير الرياضية مثل first_num + second_num. جرِّب البرنامج الآتي وراقب كيف سيتعامل مع القسمة (تذكَّر أننا نقسِّم الأعداد الصحيحة هنا) وكيف سيتعامل مع الأعداد الكبيرة. عندما تصبح الأعداد كبيرةً جدًا، فسيحدث "فيضان" (overflow) في الذاكرة كما في عدَّاد المسافة المقطوعة في السيارات عندما يتجاوز عدد الكيلومترات التي صُمِّمَ لإحصائها. حيث يبدأ من جديد، لكن يجب المرور على الأعداد السالبة في الحاسوب (ﻷن هذه هي طريقة تخزين الأعداد داخليًا في الذاكرة). تؤدي القسمة على صفر (التي لا تجوز رياضيًا) إلى ظهور خطأ. أنا متأكد أنَّك ستتعرف على أول أربع عمليات التي هي الجمع والطرح والضرب والقسمة، لكن العملية الخامسة غريبة بعض الشيء، الرمز % يُمثِّل باقي القسمة (يُسمى modulo). تُجري هذه العملية القسمة لكن بدلًا من إظهار نتيجة القسمة، فستظهِر باقي القسمة. على الرغم من أنَّ ذلك لا يبدو مفيدًا جدًا، لكنه كذلك، حيث يوفِّر أداةً مفيدةً جدًا أثناء كتابة البرامج. على سبيل المثال، عندما يُعيد باقي القسمة القيمة صفر، فهذا يُشير إلى أنَّ العدد الأول هو من مضاعفات العدد الثاني، وقد تستفيد من هذه المعلومة كثيرًا: #!/bin/bash number=0 echo -n "Enter a number > " read number echo "Number is $number" if [ $((number % 2)) -eq 0 ]; then echo "Number is even" else echo "Number is odd" fi وكذلك الأمر في برنامج يُحوِّل الثواني إلى ساعات ودقائق: #!/bin/bash seconds=0 echo -n "Enter number of seconds > " read seconds hours=$((seconds / 3600)) seconds=$((seconds % 3600)) minutes=$((seconds / 60)) seconds=$((seconds % 60)) echo "$hours hour(s) $minutes minute(s) $seconds second(s)" ترجمة -وبتصرّف- للمقال Keyboard Input And Arithmetic لصاحبه William Shotts.
  8. سنتعلم في هذا الدرس من سلسلة مدخل إلى كتابة سكربتات الصدفة كيفية إضافة "ذكاء" إلى سكربتاتنا، فإلى الآن كان يحتوي مشروعنا على سلسلة من الأوامر التي يبدأ تنفيذها من بداية الملف ويستمر سطرًا بسطر إلى أن يصل إلى نهاية الملف. لكن إمكانيات أغلبية البرامج أكبر من ما سبق، حيث تستطيع "اتخاذ القرارات" وإجراء عمليات مختلفة بناءً على مجموعة من الشروط. توفِّر الصَدَفة عدِّة أوامر يمكننا استخدامها للتحكم في جريان تنفيذ البرنامج، وسنتعلم في هذا الدرس: if test exit الأمر if أول أمر سنلقي عليه نظرةً هو الأمر if، يبدو من أول وهلة أنَّ الأمر if بسيط جدًا، لأنه يتخذ قرارًا بناءً على "حالة الخروج" (exit status) لأحد الأوامر. الشكل العام لأمر if: if commands; then commands [elif commands; then commands...] [else commands] fi حيث commands هي مجموعة أوامر. قد تبدو الأمور مربكةً بعض الشيء في البداية، لكن قبل شرح الأمر if بالتفصيل، لنلقِ نظرة على آلية معرفة الصَدَفة لنجاح أو فشل تنفيذ أمر ما. حالة الخروج تُرسِل الأوامر (بما في ذلك السكربتات ودوال الصدفة التي نكتبها) قيمة إلى النظام عند انتهاء تنفيذها تُسمى "حالة الخروج" (exit status)؛ هذه القيمة (والتي هي عدد صحيح يتراوح ما بين 0 و 255) تُشير إلى نجاح أو فشل تنفيذ الأمر. من الأعراف البرمجية أن تكون القيمة 0 تعني نجاح التنفيذ وأي قيمة أخرى تعني فشله. توفِّر الصَدَفة معاملًا (parameter) خاصًا لتفحص حالة الخروج لآخر أمر مُنفَّذ: $ ls -d /usr/bin /usr/bin $ echo $? 0 $ ls -d /bin/usr ls: cannot access /bin/usr: No such file or directory $ echo $? 2 نفَّذنا -في المثال السابق- الأمر ls مرتين، حيث نُفِّذ تنفيذًا سليمًا في أول مرة، فلو عرضنا قيمة المعامل ‎$?‎ فسنرى أنها تساوي الصفر؛ ثم نفَّذنا الأمر ls مرةً أخرى لكنه عرض رسالة خطأ وعندما طبعنا قيمة المعامل ‎$?‎ مرةً أخرى فسنرى أنَّها تساوي 2، مما يشير إلى أنَّ آخر أمر قد نُفِّذ واجه مشكلةً. تستعمل بعض الأوامر حالات خروج مختلفة لتوفير معلومات حول الخطأ، لكن العديد من الأوامر تستعمل الرقم 1 فقط للإشارة إلى باقي أنواع الأخطاء. تحتوي صفحات الدليل man عادةً على قسم مُعنوَن "Exit Status" يشرح ما هي أرقام حالات الخروج المحتملة، لكن تذكَّر أنَّ 0 تُشير دائمًا إلى نجاح التنفيذ. توفِّر الصَدَفة أمرَين مُضمَّنين فيها بسيطين للغاية، كلُ ما يفعلانه هو الانتهاء بحالة خروج 0 أو 1. ينجح تنفيذ الأمر true دائمًا ويفشل تنفيذ الأمر false دائمًا: $ true $ echo $? 0 $ false $ echo $? 1 يمكننا استخدام هذه الأوامر لتجربة عبارة if الشرطية. ما تفعله عبارة if هو أنَّها تتحقق من نجاح أو فشل تنفيذ الأوامر التي تليها: $ if true; then echo "It's true."; fi It's true. $ if false; then echo "It's true."; fi $ يُنفَّذ الأمر echo "It's true."‎ عندما يُنفَّذ الأمر الذي يلي كلمة if بنجاح، ولن يُنفَّذ عندما يفشل تنفيذ الأمر الذي يلي كلمة if. الأمر test يُستخدَم الأمر test كثيرًا مع الأمر if لإنتاج القيمة true أو false. هذا الأمر غير اعتيادي لأنَّ له شكلان مختلفان: # الشكل الأول test expression # الشكل الثاني [ expression ] آلية عمل الأمر test بسيطةٌ جدًا، فلو كان التعبير (expression) الذي يليه صحيحًا، فسينتهي تنفيذ الأمر test بحالة خروج تساوي الصفر؛ فيما عدا ذلك سينتهي بحالة خروج تساوي 1. من أهم مميزات الأمر test تنوع التعابير التي تستطيع كتابتها فيه؛ هذا مثالٌ بسيط: if [ -f .bash_profile ]; then echo "You have a .bash_profile. Things are fine." else echo "Yikes! You have no .bash_profile!" fi استخدمنا في المثال السابق التعبير ‎ -f .bash_profile الذي يقول: "هل الملف ‎.bash_profile موجود؟" فإن كان موجودًا فسينتهي الأمر test بحالة خروج تساوي الصفر (أي true) وسيُنفِّذ الأمر if الأوامر التي تتبع الكلمة then؛ وإذا لم يكن الملف موجودًا فسينتهي الأمر test بحالة خروج تساوي الواحد (أي false) وسيُنفِّذ الأمر if الأوامر التي تلي الكلمة else. هذه قائمة مختصرة بالتعابير التي يمكن استعمالها في الأمر test. ولمّا كان الأمر test مُضمَّنًا في الصَدَفة (shell builtin)، فتستطيع استخدام help test لرؤية القائمة الكاملة. ‎-d dir: الناتج هو true إذا كان dir مجلدًا. ‎-e file: الناتج هو true إذا كان file موجودًا. ‎-f file: الناتج هو true إذا كان file ملفًا عاديًا موجودًا. ‎-L file: الناتج هو true إذا كان file وصلةً رمزيةً (symbolic link). ‎-r file: الناتج هو true إذا كنت تستطيع قراءة الملف file. ‎-w file: الناتج هو true إذا كنت تستطيع الكتابة على الملف file. ‎-x file: الناتج هو true إذا كنت تستطيع تنفيذ الملف file. file1 -nt file2: الناتج هو true إذا كان الملف file1 أحدث (وفقًا لوقت التعديل [modification time]) من الملف file2. file1 -ot file2: الناتج هو true إذا كان الملف file1 أقدم من file2. ‎-z string: الناتج هو true إذا كنت السلسلة النصية string فارغة. ‎-n string: الناتج هو true إذا لم تكن السلسلة النصية string فارغة. string1 = string2: الناتج هو true إذا كانت السلسلة النصية string1 مساويةً للسلسلة النصية string2. string1 != string2: الناتج هو true إذا لم تكن السلسلة النصية string1 مساويةً للسلسلة النصية string2. قبل أن نواصل أريد أن أشرح بقية المثال السابق لأنه يبرز عددًا من الأفكار المهمة. رأينا في بداية السكربت الأمر if متبوعًا بالأمر test متبوعًا بفاصلة منقوطة وفي النهاية الكلمة then. اخترت استعمال الشكل [ expression ] للأمر test لأنَّ أغلبية الناس يرون أنَّ قراءته أسهل. لاحظ أنَّ الفراغات مطلوبة بين قوس البداية ] وبداية التعبير، وكذلك الفراغ بين نهاية التعبير وقوس الإغلاق [. تعمل الفاصلة المنقوطة كفاصل بين الأوامر، مما يسمح بوضع أكثر من أمر في نفس السطر. مثلًا: $ clear; ls سيؤدي إلى مسح الشاشة ثم تنفيذ الأمر ls. استخدمتُ الفاصلة المنقوطة في عبارة if السابقة لأنني أريد وضع الكلمة then في نفس سطر الأمر if لأنني أرى أنَّها قراءتها أسهل بهذه الطريقة. سنشاهد صديقنا القديم echo في السطر الثاني، لكنك ستلاحظ وجود محاذاة (أي فراغات قبل الأمر)، وهذا لغرض تسهيل قابلية القراءة، ومن التقاليد البرمجية أن نحاذي جميع الأوامر داخل العبارة الشرطية if (أي جميع الأسطر التي ستُنفَّذ عند تحقيق شرط معيّن). تذكَّر أنَّ الصَدَفة لا تتطلَّب فعل ذلك، لكننا نفعله لجعل قراءة الشيفرة أسهل. بعبارة أخرى، يمكننا كتابة الشيفرات الآتية وسنحصل على نفس النتيجة: # Alternate form if [ -f .bash_profile ] then echo "You have a .bash_profile. Things are fine." else echo "Yikes! You have no .bash_profile!" fi # Another alternate form if [ -f .bash_profile ] then echo "You have a .bash_profile. Things are fine." else echo "Yikes! You have no .bash_profile!" fi الأمر exit لكي نكتب سكربتات صدفة جيدة، فعلينا ضبط حالة خروج عندما ينتهي تنفيذ السكربت، ونستعمل الأمر exit لفعل ذلك، الذي يؤدي إلى إيقاف تنفيذ السكربت فوريًا وضبط حالة الخروج إلى القيمة المُمرَّرة كوسيط إليه. على سبيل المثال، الأمر الآتي: exit 0 سيؤدي إلى إيقاف تنفيذ السكربت وضبط حالة الخروج إلى 0 (أي نجاح التنفيذ)، بينما: exit 1 سيؤدي إلى إيقاف تنفيذ السكربت وضبط حالة الخروج إلى 1 (أي فشل التنفيذ). التحقق من أن المستخدم المشغل للسكربت هو الجذر آخر مرة تركنا فيها السكربت كنا نحتاج إلى تشغيله بامتيازات الجذر، وذلك لأنَّ الدالة home_space تحتاج إلى معرفة المساحة التخزينية التي تستهلكها مجلدات المنزل للمستخدمين. لكن ماذا سيحدث لو حاول مستخدمٌ عادي تشغيل السكربت؟ سيؤدي ذلك إلى إظهار الكثير من رسائل الخطأ القبيحة. لكن ماذا لو وضعنا شيئًا في السكربت يمنع تنفيذه من المستخدم العادي؟ الأمر id يخبرنا من هو المستخدم الحالي، وعند تمرير الخيار ‎-u إليه فسيطبع قيمة عددية لمُعرِّف المستخدم (user ID) الحالي. $ id -u 501 $ su Password: # id -u 0 فلو نفَّذ المستخدم الجذر الأمر id -u فسيكون الناتج هو 0، ويمكننا أن نستثمر هذه المعلومة لكي تكون الأساس الذي سنبني عليه الاختبار الذي سنضعه في السكربت: if [ $(id -u) = "0" ]; then echo "superuser" fi تحققنا في المثال السابق أنَّ ناتج الأمر id -u مساوٍ للسلسلة النصية "0" ثم طبعنا العبارة "superuser". وعلى الرغم من أنَّ الأمر السابق يكتشف إن كان المستخدم هو المستخدم الجذر، إلا أنَّه لم يحل المشكلة بعد. إذ نريد أن يتوقف تنفيذ السكربت إن لم يكن المستخدم المُشغِّل له هو الجذر، لذلك نكتب الشيفرة الآتية: if [ $(id -u) != "0" ]; then echo "You must be the superuser to run this script" >&2 exit 1 fi نتحقق في الشيفرة السابقة أنَّ ناتج الأمر id -u لا يساوي "0"، ثم سيطبع السكربت رسالة خطأ مفهومة، ثم ينتهي تنفيذه بحالة خروج مساوية للواحد، لكي يخبر النظام أنَّه لم يتم التنفيذ بنجاح. لاحظ وجود ‎>&2 في نهاية الأمر echo، الذي هو شكلٌ من أشكال إعادة توجيه الدخل والخرج (I/O redirection)، وسترى هذا التعبير عادةً في نهاية الأوامر التي تطبع رسائل خطأ، لأننا لو لم نُعِد توجيه مجرى الخطأ هنا، فسترسَل رسالة الخطأ إلى مجرى الخرج القياسي (standard output stream)، لكننا نريد أن تظهر رسائل الخطأ بمعزل عن مخرجات السكربت، لأننا نعيد توجيه مجرى الخرج القياسي الناتج من تنفيذ السكربت إلى ملف. علينا أن نضع الأسطر السابقة في بداية السكربت لكي نتمكن من تحديد هوية المستخدم المُشغِّل قبل أن يقع الخطأ، لكننا نريد في الوقت نفسه أنَّ يمكن المستخدمون العاديون من تشغيل السكربت، لذلك سنعدِّل الدالة home_space لكي تتأكد من امتيازات المستخدم كالآتي: function home_space { # Only the superuser can get this information if [ "$(id -u)" = "0" ]; then echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" fi } # end of home_space بهذه الطريقة سيتمكن المستخدم العادي من تشغيل السكربت، وسيتم تجاوز الشيفرة التي قد تتسبب بخطأ بدلًا من تنفيذها وإظهار رسالة للمستخدم. ترجمة -وبتصرّف- للمقال Flow Control - Part 1 لصاحبه William Shotts.
  9. بعد أن ازدادت السكربتات التي نكتبها تعقيدًا، فأحببت أن أشير إلى بعض الأخطاء الشائعة التي قد تصادفك أثناء مسيرتك. سنتعرض في هذا الدرس مثالًا ونعمل على تحليل الأخطاء التي قد نرتكبها، ولنسمِّ ذاك السكربت trouble.bash، تأكد من كتابة السكربت كما هو موجود حرفيًا. #!/bin/bash number=1 if [ $number = "1" ]; then echo "Number equals 1" else echo "Number does not equal 1" fi يجب أن يُخرِج السكربت السابق السطر "Number equals 1"، لأنَّ المتغير number يساوي 1، إن لم تحصل على المخرجات التي توقعتها، فتحقق من صحة كتابتك للسكربت، فربما ارتكبتَ خطأً… المتغيرات الفارغة عدِّل السطر الثالث من السكربت من: number=1 إلى: number= ثم شغِّل السكربت مرةً أخرى، وستحصل هذه المرة على المخرجات الآتية: $ ./trouble.bash /trouble.bash: [: =: unary operator expected. Number does not equal 1 كما لاحظت، عَرَضَت الصَدَفة bash رسالة خطأ عندما شغلنا السكربت، وربما ظننتَ أنَّ حذف القيمة "1" من السطر الثالث قد أدى إلى خطأٍ بنيوي (syntax error) لكن هذا ليس صحيحًا، ألقِ نظرةً إلى رسالة الخطأ مجددًا: ./trouble.bash: [: =: unary operator expected يمكننا ملاحظة أنَّ ‎./trouble.bash يُبلِّغ عن الخطأ، الذي يرتبط -بشكلٍ أو بآخر- مع ]؛ تذكَّر أنَّ ] هو اختصارٌ للأمر المُضمَّن في الصَدَفة test. ومن رسالة الخطأ السابقة استطعنا تحديد أنَّ الخطأ يحدث في السطر الخامس وليس الثالث. عليّ القول بادئ الأمر أنَّه لا توجد أيّة مشكلة في السطر الثالث، حيث number=‎ صحيحة بنيويًا؛ فقد ترغب في بعض الأحيان بحذف القيمة المُخزَّنة في متغيّر. يمكنك التحقق من سلامة هذه الصياغة بكتابتها وتجربتها في سطر الأوامر: $ number= $ أرأيت! لا توجد رسالة خطأ، لكن ما هو الشيء الخاطئ في السطر الخامس؟ لقد جربناه قبل تعديل السكربت ولم يكن يسبب أيّة مشاكل. لكي نفهم هذا الخطأ، علينا أن ننظر إلى الموضوع من وجهة نظر الصَدَفة. وَضَعَت الصَدَفة، في السطر الخامس، قيمة المتغير number عندما رأت ‎$number. ففي أول محاولة لتشغيل السكربت (أي عندما كان number=1)، بدَّلَت الصدفة المتغير ‎$number بالرقم 1 كما يلي: if [ 1 = "1" ]; then لكننا عندما أزلنا قيمة المتغير (number=‎)، فستحاول الصدفة تنفيذ ما يلي: if [ = "1" ]; then وهذا خطأ، ويُفسِّر أيضًا ما تبقى من رسالة الخطأ التي حصلنا عليها. المُعامِل = هو معامِل ثنائي، الذي يعني أنَّه يتوقع وجود عنصرين (كل عنصر على طرف). وما تحاول الصَدَفة إخبارنا به هو أنَّ هنالك عنصرٌ واحدٌ فقط، ولهذا يجب وضع معامل أحادي (مثل !) الذي يتطلب وجود عنصر وحيد فقط. علينا تعديل السطر الخامس إلى ما يلي لحل هذه المشكلة: if [ "$number" = "1" ]; then وسترى الصَدَفة ما يلي (إذا كانت قيمة number=‎): if [ "" = "1" ]; then وبهذا تجنبنا هذا الخطأ. تعلمنا من هذا الخطأ أمرًا مهمًا عند كتابة السكربتات: خذ بعين الاعتبار ماذا سيحدث لو كانت قيمة أحد المتغيرات فارغة. غياب إحدى علامات الاقتباس عدِّل السطر السادس وأزل علامة إغلاق الاقتباس من نهاية السطر: echo "Number equals 1 ثم شغِّل السكربت مرةً أخرى وستحصل على: $ ./trouble.bash ./trouble.bash: line 8: unexpected EOF while looking for matching " ./trouble.bash: line 10 syntax error: unexpected end of file هذه مشكلةٌ أخرى شائعةٌ تُسبِّب مشاكل في أماكن أخرى في السكربت. ماذا يحدث لو استمرت الصَدَفة بحثها عن علامة إغلاق الاقتباس لمعرفة نهاية سلسلةٍ نصيةٍ ما، لكنها وصلت إلى نهاية الملف ولم تجدها. يصعب كثيرًا اكتشاف هذا النوع من الأخطاء في السكربتات الطويلة؛ وهذا أحد الأسباب التي تدفعك لتجربة السكربتات بين الحين والآخر عندما تكتبها لوجود كمية قليلة من الشيفرات الجديدة التي عليك اختبارها. أرى أيضًا أنَّ استخدام المحررات النصيّة التي توفِّر تلوينًا للشيفرات يساعد كثيرًا في الكشف عن مثل هذه الأخطاء. عزل مكان المشكلة قد تكون عملية إيجاد الأخطاء والعِلل في برنامجك صعبة ومحبطة، هذه بعض التقنيات التي قد تستفيد منها: اعزل أجزاءً من الشيفرات بوضع علامة تعليق قبل الأسطر التي لا تريد أن تنفذها الصَدَفة. طبِّق هذا على كتلة من الشيفرات لكي ترى إن اختفت مشكلة معيّنة. وبهذه الآلية ستعرف ما هو الجزء الذي يسبب (أو لا يسبب) المشكلة. على سبيل المثال، لو عدنا إلى السكربت الذي فيه علامة اقتباس ناقصة، فيمكننا أن نعزل المشكلة كالآتي: #!/bin/bash number=1 if [ $number = "1" ]; then echo "Number equals 1 #else # echo "Number does not equal 1" fi سنعلم بعد وضع عبارة else في تعليق ثم تشغيل السكربت أنَّ المشكلة ليس في عبارة else حتى لو أشارت رسالة الخطأ إلى ذلك. استخدم الأمر echo للتحقق من القيم. فبعد أن تكتسب خبرة في تتبع العلل، ستكتشف أنَّ العلل ستتواجد في مكانٍ مختلف عن المكان الذي تتوقع وجودها فيه. إحدى المشاكل الشائعة هي افتراضك أنَّ التسلسل المنطقي لبرنامجك صحيحٌ تمامًا، وعندما ترى مشكلة في مرحلة ما في البرنامج فستفترض أنَّها موجودة هناك؛ وهذا خاطئ في معظم الحالات. يمكنك وضع أوامر echo في الشيفرة أثناء محاولة تنقيح (debugging) الأخطاء لكي تحصل على رسائل تؤكد لك أنَّ البرنامج يعمل كما تتوقع. هنالك نوعان من الرسائل التي عليك وضعها. الغرض من أول نوع هو الإعلان أنَّ التنفيذ قد وصل إلى مكان معيّن في البرنامج، ولقد رأينا ذلك سابقًا عند كتابتنا لشيفرات وهمية في الدوال التي أضفناها. وهذا مفيد لكي تعلم أنَّ مسار تنفيذ البرنامج مماثل تمامًا لما نتوقعه. النوع الثاني يعرض قيم المتغيرات المستخدمة في الحسابات أو الاختبارات. قد تجد في بعض الأحيان قسمًا من السكربت لا يُنفَّذ تنفيذًا سليمًا لأنك افترضت أنَّ شيئًا ما في ما سبقه من الشيفرات صحيحٌ؛ إلا أنَّ فيه مشكلةً تؤدي إلى فشل تنفيذ ما يليه من الشيفرات. مراقبة تشغيل السكربت من الممكن أنَّ تعرض لك bash ما الذي يحدث عندما تُشغِّل السكربت. وذلك بإضافة الخيار ‎-x في أول سطر من السكربت كما يلي: #!/bin/bash -x وعندما ستُشغِّل السكربت، فستعرض bash كل سطر ستحاول تنفيذه (بعد تعويض قيم المتغيرات…). تُسمى هذه التقنية بالتتبع (tracing)، وهذا مثالٌ عنها: $ ./trouble.bash + number=1 + '[' 1 = 1 ']' + echo 'Number equals 1' Number equals 1 تستطيع أيضًا أن تستعمل الأمر set داخل السكربت لتفعيل أو تعطيل التتبع. استخدم set -x لتشغيل التتبع و set +x لتعطيل التتبع، مثال: #!/bin/bash number=1 set -x if [ $number = "1" ]; then echo "Number equals 1" else echo "Number does not equal 1" fi set +x ترجمة -وبتصرّف- للمقال Stay Out Of Trouble لصاحبه William Shotts.
  10. عندما يزداد طول البرامج وتعقيدها، فستزداد صعوبة تصميمها وبرمجتها وصيانتها؛ لذا من المفيد عادةً تقسيم المهام الكبيرة إلى سلسلة من المهام الأصغر. سنُقسِّم في هذا الدرس السكربت الذي كنا نعمل عليه إلى عدد من الدوال (functions) المنفصلة. لكي نتعرف على مفهوم الدوال، فلنحاول وصف طريقة القيام بمهمة يومية: الذهاب إلى السوق وشراء الطعام. تخيل أننا سنصف العملية إلى كائنات فضائية آتية من المريخ. سيبدو الوصف العام لعملية شراء الطعام كالآتي: غادر المنزل قد السيارة إلى السوق اركن السيارة ادخل السوق اشترِ طعامًا قد السيارة إلى المنزل اركن السيارة ادخل إلى المنزل سيُغطِّي الشرح السابق الآلية العامة للذهاب إلى السوق؛ لكن تلك الكائنات الفضائية ستحتاج مزيدًا من التفاصيل، فمثلًا يمكن وصف المهمة الفرعية "اركن السيارة" كالآتي: اعثر على مكان فارغ لركن السيارة قد السيارة إلى ذاك المكان أطفئ المحرك "ارفع" المكابح اليدوية اخرج من السيارة اقفل السيارة ويمكن بالطبع تقسيم خطوة "أطفئ المحرك" إلى عدد من الخطوات مثل: أطفئ دارة الإشعال أخرج مفتاح السيارة وهكذا إلى أن تُفصِّل كل خطوة من كامل عملية الذهاب إلى السوق. عملية تعريف الخطوط الأساسية ومن ثم كتابة التفاصيل لتلك الخطوات تسمى "نمط تصميم Top-Down". يسمح هذا النمط لنا بتقسيم المهام الكبيرة والضخمة إلى مهام أبسط وأصغر. سنستخدم نمط تصميم Top-Down ليساعدنا في التخطيط لبرنامجنا الذي سنكمل تطويره وإضافة الميزات إليه. يمكننا تلخيص "الوصف العام" للمهام التي يقوم بها السكربت الآن: بداية الصفحة بداية ترويسة الصفحة كتابة العنوان إغلاق الترويسة بداية جسم الصفحة كتابة العنوان كتابة بصمة الوقت (timestamp) إغلاق الجسم إغلاق الصفحة تمت برمجة كل الخطوات السابقة، لكننا نريد إضافة المزيد. لندرج بعض المهام الإضافية بعد المهمة السابعة: كتابة بصمة الوقت كتابة معلومات عن إصدار النظام كتابة الوقت الذي مضى منذ آخر تشغيل (uptime) كتابة مساحة القرص كتابة المساحة التخزينية لمجلدات المنزل (home) إغلاق الجسم إغلاق الصفحة سيكون من حسن حظنا وجود أوامر تستطيع تنفيذ المهام الإضافية، فسنستطيع استخدام "تعويض الأوامر" (command substitution) لوضعها في السكربت كالآتي: #!/bin/bash # sysinfo_page - A script to produce a system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ أما للمهام التي لا توجد أوامر تستطيع فعل ما نريد تحديدًا، فيمكننا إنشاؤها باستخدام دوال الصدفة (shell functions). وكما تعلمنا في أحد الدروس السابقة، يمكن اعتبار دوال الصدفة على أنها "برامج صغيرة ضمن البرامج" وتسمح لنا باتباع مبادئ نمط التصميم top-down. علينا تعديل السكربت كالآتي لإضافة دوال الصدفة: #!/bin/bash # sysinfo_page - A script to produce an system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { } show_uptime() { } drive_space() { } home_space() { } ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ هنالك نقطتان تجدر الإشارة إليهما: أولهما أنَّه يجب تعريف دوال الصدفة قبل محاولة استخدامها؛ وثانيهما هو أنَّ جسم الدالة (أي القسم الذي يقع بين قوس البداية "}" وقوس النهاية "{") يجب أن يحتوي على أمرٍ واحدٍ على الأقل. لن يعمل السكربت السابق وسيُظهِر رسالة خطأ وذلك لأنَّ جسم الدوال فارغ. أبسط طريقة لتصحيح هذه المشكلة هي وضع عبارة "return" في جسم كل دالة، وبعدها سيُنفَّذ السكربت بنجاح. إبقاء السكربتات قابلة للتشغيل من المفيد أثناء تطويرنا للتطبيق أن نُضيف جزءًا يسيرًا من الشيفرات ثم نُجرِّب السكربت ثم نضيف المزيد ثم نجرِّب السكربت وهكذا. وبهذه الطريقة سيسهل العثور على الأخطاء في الشيفرة ومن ثم تصحيحها. بعد إضافة الدوال إلى السكربت، أصبح بإمكانك الآن مراقبة التسلسل المنطقي لتنفيذ السكربت وذلك عبر آلية يُطلَق عليها اسم stubbing أي إضافة شيفرة وهمية. يمكنك تخيل هذه الآلية كما يلي: لنفترض أننا نريد إنشاء دالة اسمها "system_info" لكننا لم نفكر في تفاصيل الشيفرة بشكل كامل. فبدلًا من إيقاف عملية تطوير السكربت إلى أن ننتهي من الدالة system_info فيمكننا إضافة الأمر echo إليها كالآتي: system_info() { # Temporary function stub echo "function system_info" } سنتمكن باستخدام هذه الآلية من تنفيذ السكربت دون خطأ حتى لو لم نكمل برمجة الدالة system_info؛ ونستطيع لاحقًا وضع الشيفرة الحقيقية بدلًا من أمر echo السابق. سبب استخدامنا لأمر echo هو أننا نحتاج إلى مؤشر لكي نعرف أنَّ السكربت قد نفَّذ الدالة المعنية. لنُطبِّق هذه الآلية على جميع الدوال في السكربت: #!/bin/bash # sysinfo_page - A script to produce an system information HTML file ##### Constants TITLE="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" ##### Functions system_info() { # Temporary function stub echo "function system_info" } show_uptime() { # Temporary function stub echo "function show_uptime" } drive_space() { # Temporary function stub echo "function drive_space" } home_space() { # Temporary function stub echo "function home_space" } ##### Main cat <<- _EOF_ <html> <head> <title>$TITLE</title> </head> <body> <h1>$TITLE</h1> <p>$TIME_STAMP</p> $(system_info) $(show_uptime) $(drive_space) $(home_space) </body> </html> _EOF_ سنكمل الآن العمل على كل دالة على حدة لكي تُخرِج معلوماتٍ مفيدةً. show_uptime ستُظهِر الدالة show_uptime ناتج الأمر uptime، الذي يعرض عدِّة معلومات مثيرة للاهتمام حول النظام، بما في ذلك المدة الزمنية منذ آخر إعادة تشغيل، وعدد المستخدمين، والحِمل (load) الحالي على النظام. $ uptime 9:15pm up 2 days, 2:32, 2 users, load average: 0.00, 0.00, 0.00 لعرض ناتج الأمر uptime في صفحة HTML، فسنحتاج إلى برمجة دالة الصدفة كالآتي (وذلك بعد حذف الشيفرة الوهمية التي كانت فيها): show_uptime() { echo "<h2>System uptime</h2>" echo "<pre>" uptime echo "</pre>" } كما ترى، تُخرِج الدالة السابقة نصًا يحتوي على خليطٍ من وسوم HTML مع مخرجات الأمر uptime؛ وستصبح هذه المخرجات جزءًا من here script عندما تُجرى عملية "تعويض الأوامر" في الجزء الرئيسي من السكربت. drive_space تستخدم الدالة drive_space الأمر df لتوفير ملخص للمساحة التخزينية المستهلكة من أنظمة الملفات الموصولة (mounted file systems). $ df Filesystem 1k-blocks Used Available Use% Mounted on /dev/hda2 509992 225772 279080 45% / /dev/hda1 23324 1796 21288 8% /boot /dev/hda3 15739176 1748176 13832360 12% /home /dev/hda5 3123888 3039584 52820 99% /usr ستبدو بنية دالة dive_space شبيهةً للغاية بدالة show_uptime: drive_space() { echo "<h2>Filesystem space</h2>" echo "<pre>" df echo "</pre>" } home_space ستُظهِر دالة home_space مقدار المساحة التخزينية التي يستهلكها كل مستخدم في مجلد المنزل الخاص به. سيُعرَض الناتج كقائمة مرتبة تنازليًا وفق مقدار المساحة التخزينية المستخدمة. home_space() { echo "<h2>Home directory space by user</h2>" echo "<pre>" echo "Bytes Directory" du -s /home/* | sort -nr echo "</pre>" } لاحظ أنَّه يجب تنفيذ السكربت عبر مستخدم يملك امتيازات إدارية لكي تعمل الدالة السابقة بشكلٍ صحيح، لأنَّ الأمر du يتطلب امتيازات الجذر (root) لكي يتفحص محتويات المجلد ‎/home. system_info لسنا جاهزين بعد لإكمال دالة system_info. لكننا سنُحسِّن من الشيفرة الوهمية التي فيها لكي تُنتِج وسوم HTML: system_info() { echo "<h2>System release info</h2>" echo "<p>Function not yet implemented</p>" } ترجمة -وبتصرّف- للمقالَين Shell Functions و Some Real Work لصاحبهما William Shotts.
  11. رأينا في الدرس السابق كيف كتبنا سكربتًا يولِّد صفحة HTML، لكن هذا ليس كافيًا لنا، فلنقم ببعض التعديلات. #!/bin/bash # sysinfo_page - A script to produce an HTML file cat <<- _EOF_ <html> <head> <title> My System Information </title> </head> <body> <h1>My System Information</h1> </body> </html> _EOF_ هل لاحظت كيف أنَّ العبارة "My System Information" مكررة مرتين في السكربت السابق؟ لنُحسِّنها هكذا: #!/bin/bash # sysinfo_page - A script to produce an HTML file title="My System Information" cat <<- _EOF_ <html> <head> <title> $title </title> </head> <body> <h1>$title</h1> </body> </html> _EOF_ أضفنا سطرًا إلى بداية السكربت ووضعنا ‎$title بدلًا من العبارة "My System Information". المتغيرات ما فعلناه في الأعلى سيمهد لنا الطريق لشرح فكرة أساسية جدًا موجودة في جميع لغات البرمجة تقريبًا: المتغيرات (variables). المتغيرات هي أماكن في الذاكرة يمكن أن تُستعمَل لتخزين المعلومات، ويُشار إليها باسمٍ مُميِّزٍ لها. أنشأنا في السكربت السابق متغيرًا اسمه title ووضعنا العبارة "My System Information" في الذاكرة، ثم استخدمنا ‎$title لإخبار الصَدَفة أننا نريد إجراء "توسعة المعاملات" (parameter expansion) ونضع محتوى المتغير بدلًا من اسمه. عندما ترى الصَدَفة كلمةً تبدأ برمز $ فستحاول معرفة إذا كانت تُشير تلك الكلمة إلى متغير، ثم ستضع القيمة المُخزَّنة فيه -أي المتغير- مكان ورود تلك الكلمة. كيفية إنشاء متغير كل ما عليك فعله لإنشاء متغير هو وضع اسم المتغير في سطرٍ مستقل متبوعًا برمز المساواة (=) دون أيّة فراغات، ثم كتابة المعلومات التي تريد إسنادها بعد رمز المساواة. أسماء المتغيرات حسنًا، أنت من يُسمي المتغيرات، لكن هنالك بعض القواعد التي عليك مراعاتها: يجب أن تبدأ أسماء المتغيرات بحرف. يجب ألّا يحتوي اسم المتغير على فراغات. استخدم الشرطات السفلية (_) بدلًا منها. لا تستطيع استخدام علامات الترقيم. كيف أثر المتغير على السكربت الذي نكتبه سهَّلت إضافة المتغير title الأمر علينا من ناحيتين: الأولى هي تقليل مقدار الكتابة الذي نحتاجه، والثانية (وهي المهمة) هي أننا جعلنا صيانة السكربت أسهل. كلما ازدادت خبرتك في كتابة سكربتات الشِل (أو أي لغة برمجة أخرى)، فستتعلم أنَّك لا تنتهي من كتابة البرنامج في خطوة واحدة، فهنالك تعديلات وتحسينات من قبِل كاتب البرنامج أو من غيره؛ وهذا هو حجر الأساس لعملية تطوير البرمجيات مفتوحة المصدر. فلنقل مثلًا أنَّك تريد تغيير العبارة "My System Information" إلى "Linuxbox System Information"، فكنت تحتاج -في النسخة القديمة من السكربت- إلى تغيير تلك العبارة في مكانين منفصلين، أما في النسخة الجديدة التي فيها المتغير title فلا حاجة إلى تغيير تلك العبارة إلا في مكانٍ وحيد. قد تظن أنَّ هذا التغيير تافه أو ليس له فائدة حقيقية، لكن ذلك لأنَّ السكربت الذي نكتبه ما يزال بسيطًا وقصيرًا؛ لكن التنظيم أساسيٌ جدًا في السكربتات الكبيرة والمعقدة. متغيرات البيئة Environment Variables هنالك بعض المتغيرات المضبوطة في جلسة الصَدَفة من قِبل ملفات البدء التي رأيناها سابقًا. استعمل الأمر printenv لرؤية جميع المتغيرات الموجودة في البيئة عندك؛ يحتوي أحد تلك المتغيرات "اسم المضيف" (hostname) لنظامك؛ ونستطيع أن نُضيف ذاك المتغير إلى السكربت كالآتي: #!/bin/bash # sysinfo_page - A script to produce an HTML file title="System Information for" cat <<- _EOF_ <html> <head> <title> $title $HOSTNAME </title> </head> <body> <h1>$title $HOSTNAME</h1> </body> </html> _EOF_ أصبح السكربت الآن يضع اسم الحاسوب الذي نعمل عليه في صفحة HTML الناتجة. لاحظ أنَّ أسماء متغيرات البيئة (وفق التقاليد البرمجية) تُكتَب بأحرفٍ كبيرة. تعويض الأوامر سنحاول الآن تحسين السكربت بوضع ناتج من أحد الأوامر فيه. كانت آخر نسخة من السكربت قادرةً على إنشاء صفحة HTML تحتوي على أسطر نصية بسيطة تتضمن اسم المضيف لجهازنا المأخوذ من متغير البيئة المسمى HOSTNAME، سنُحدِّث السكربت الآن لإضافة بصمة وقت إلى الصفحة لكي تُشير إلى آخر تحديث لها، مع ذكر اسم المستخدم الذي قام بالتحديث. #!/bin/bash # sysinfo_page - A script to produce an HTML file title="System Information for" cat <<- _EOF_ <html> <head> <title> $title $HOSTNAME </title> </head> <body> <h1>$title $HOSTNAME</h1> <p>Updated on $(date +"%x %r %Z") by $USER</p> </body> </html> _EOF_ كما لاحظت، استعملنا متغير بيئة جديد هو USER لكي نحصل على اسم المستخدم؛ واستعملنا تعبيرًا غريب المظهر: $(date +"%x %r %Z") المحارف ‎$()‎ تقول "يجب وضع ناتج الأمر المُحاط بالأقواس هنا". وأردنا في السكربت السابق وضع ناتج الأمر date +"%x %r %Z"‎ الذي يطبع التاريخ والوقت الحاليين. لدى الأمر date ميزاتٌ وخياراتُ تنسيقٍ كثيرة، نستطيع إلقاء نظرة عليها كالآتي: $ date --help | less لاحظ أنَّ هنالك صيغة قديمة بديلة عن (‎$(command هي استخدام علامة الاقتباس الخلفية "`"، هذه الصيغة القديمة متوافقة مع صَدَفة Bourne Shell الأصلية (sh)؛ لكنني لا أنوي استخدام الشكل القديم لأنني أشرح استخدام bash الحديثة وليس sh. تدعم صَدَفة bash جميع السكربتات المكتوبة لـ sh، ولهذا تكون الصيغتان الآتيتان متكافئتين: $(command) `command` إسناد ناتج أحد الأوامر إلى متغير يمكننا أيضًا إسناد ناتج أحد الأوامر إلى متغير: right_now=$(date +"%x %r %Z") نستطيع أيضًا وضع متغير داخل متغير آخر كما يلي: right_now=$(date +"%x %r %Z") time_stamp="Updated on $right_now by $USER" الثوابت كما يوحي اسم "المتغيرات": قيمة المتغير قابلة للتبديل، وهذا يعني أنَّه من المحتمل أثناء تنفيذ السكربت أن تُعدَّل قيمة المتغير نتيجةً لعمليةٍ قمتَ بها. في المُقابل، هنالك قيم يجب ألّا تتغير بعد ضبطها، وتسمى "الثوابت" (constants). سبب ذكري لهذا الموضوع هو أنَّ مفهوم الثوابت شائعٌ في البرمجة، وتدعمها أغلبية لغات البرمجة، لكن لكي أكون صريحًا معك، لم أشاهد استعمالًا عمليًا لها. فلو كان من المفترض أن تبقى قيم المتغير ثابتةً فسيسمى المتغير بأحرفٍ كبيرة لتذكير المبرمج أنَّ قيمة المتغير ثابتة. تُعتبَر متغيرات البيئة ثوابتَ لأنها نادرًا ما تتغير؛ وتُعطى الثوابت أسماءً ذات أحرفٍ كبيرة عادةً. سأستعمل العرف الآتي في هذا السكربت: الأحرف الكبيرة للثوابت والأحرف الصغيرة للمتغيرات. يبدو السكربت الذي نعمل عليه كالآتي حاليًا: #!/bin/bash # sysinfo_page - A script to produce an HTML file title="System Information for $HOSTNAME" RIGHT_NOW=$(date +"%x %r %Z") TIME_STAMP="Updated on $RIGHT_NOW by $USER" cat <<- _EOF_ <html> <head> <title> $title </title> </head> <body> <h1>$title</h1> <p>$TIME_STAMP</p> </body> </html> _EOF_ ترجمة -وبتصرّف- للمقالَين Variables و Command Substitution And Constants لصاحبهما William Shotts.
  12. سنشرع في بناء تطبيق مفيد بدءًا من هذا الدرس، سيُنتِج هذا التطبيق مستند HTML يحتوي على معلومات عن نظامك. قضيتُ وقتًا طويلًا في التفكير حول الطريقة التي عليّ اتباعها لشرح برمجة سكربتات الصدفة، ووجدت أنَّ الطريقة التي اعتمدتها مختلفة عن أغلبية الشروحات التي رأيتها، فالأغلبية تُفضِّل شرحًا هيكليًا لمختلف ميزات الصَدَفة bash، ويفترضون أنَّ لديك معرفة مسبقة مع إحدى لغات البرمجة؛ وعلى الرغم من أنني لا أعتبر أنَّ لديك خلفية برمجية، إلا أنني مدرك أنَّ نسبة كبيرة من الأشخاص العاملين في مجال التقنية يعرفون البنية الأساسية لصفحات HTML، لذلك سيُنتِج برنامجنا صفحة ويب. سنكتشف ميزات الصَدَفة bash أثناء بنائنا للسكربت، وسنتعرف على الأدوات اللازمة لحل المشكلات التي ستواجهنا. كتابة ملف HTML باستخدام سكربت كما تعلم، تكون بنية ملف HTML كالآتي: <html> <head> <title> The title of your page </title> </head> <body> Your page content goes here. </body> </html> بأخذ ذلك بعين الاعتبار، يمكننا أن نكتب سكربتًا يمكنه إخراج المحتوى السابق: #!/bin/bash # sysinfo_page - A script to produce an html file echo "<html>" echo "<head>" echo " <title>" echo " The title of your page" echo " </title>" echo "</head>" echo "" echo "<body>" echo " Your page content goes here." echo "</body>" echo "</html>" يمكن أن يُستخدم السكربت كالآتي (تذكَّر أنَّ الرمز < هو رمز إعادة توجيه المخرجات، وهنا سنعيد توجيه المخرجات إلى ملف باسم sysinfo_page.html): $ sysinfo_page > sysinfo_page.html قيل أنَّ أعظم المبرمجين قدرًا هم أكسلهم! حيث يكتبون برامج ليريحوا أنفسهم من بعض الأعمال؛ وبالمثِل: عندما يكتب المبرمجون الأذكياء برنامجًا، فإنهم يحاولون تقليل مقدار الكتابة التي يكتبونها. أول تحسين سنفعله للسكربت هو التخلص من الاستعمال المتكرر لأمر echo والاستعاضة عنه بأمرٍ واحد (سنحيط كامل مستند HTML بعلامات اقتباس): #!/bin/bash # sysinfo_page - A script to produce an HTML file echo "<html> <head> <title> The title of your page </title> </head> <body> Your page content goes here. </body> </html>" أصبح من الممكن احتواء الأسطر الجديدة في النص داخل علامتَي الاقتباس، وبهذا يمكن أن يمتد الوسيط (argument) المُمرَّر إلى الأمر echo على أكثر من سطر. بغض النظر أنَّ ما سبق تحسينٌ واضحٌ، إلا أنَّ فيه قصورًا لأنَّ شيفرات HTML تحتوي عادةً على علامات اقتباس، مما يجعلها تتعارض مع علامات الاقتباس المحيطة بالوسيط، لكن يمكننا "تهريب" (escape) علامة الاقتباس بوضع شرطة خلفية مائلة \ قبلها. لكننا نريد تجنب كتابة المزيد من الأحرف! إذًا علينا البحث عن طريقة أفضل لطباعة النص. لحسن الحظ توفر لنا الصَدَفة bash طريقةً لفعل ذلك اسمها here script. #!/bin/bash # sysinfo_page - A script to produce an HTML file cat << _EOF_ <html> <head> <title> The title of your page </title> </head> <body> Your page content goes here. </body> </html> _EOF_ here script (يُسمى أحيانًا here document) هو شكل من أشكال إعادة توجيه المخرجات، الذي يوفِّر طريقةً لتضمين محتوى سيُمرِّر إلى مجرى الدخل القياسي (standard input stream) لأحد الأوامر. مُرِّرَت -في المثال السابق- كتلةٌ نصيةٌ إلى مجرى الدخل القياسي للأمر cat. الشكل العام لإنشاء here script: command << token content to be used as command's standard input token يمكن اختيار أي سلسلة نصية لكي تكون العلامة الرمزية (token)، لكنني استخدمت __EOF__ ‏(EOF هو اختصارٌ شهير للعبارة End Of File أي نهاية الملف) لشيوعها، لكنك تستطيع استخدام أي سلسلة تشاء، لطالما أنَّها لا تتعارض مع كلمةٍ محجوزةٍ في bash. العلامة الرمزية التي تُنهي here script يجب أن تُطابِق تمامًا تلك التي بدأته، وإلا فستعامل محتويات السكربت المتبقية على أنَّها دخل قياسي للأمر المُحدَّد. هنالك خدعة إضافية يمكنك استخدامها مع here script تسمح لك بمحاذاة (indent) المحتوى المُمرَّر عبر here script لتحسين قابلية قراءة السكربت. يمكنك فعل ذلك بتعديل السكربت كالآتي: #!/bin/bash # sysinfo_page - A script to produce an HTML file cat <<- _EOF_ <html> <head> <title> The title of your page </title> </head> <body> Your page content goes here. </body> </html> _EOF_ تبديل علامة ‎>> إلى ‎<<-‎ سيؤدي إلى تجاهل مسافات الجدولة (tab) البادئة (لكن لن يتم تجاهل الفراغات) في here script؛ لن يحتوي ناتج الأمر cat على أيّة مسافات جدولة بادئة. حسنًا، لنُعدِّل محتويات ملف HTML لكي نبيّن ما الغرض من صفحة الويب: #!/bin/bash # sysinfo_page - A script to produce an HTML file cat <<- _EOF_ <html> <head> <title> My System Information </title> </head> <body> <h1>My System Information</h1> </body> </html> _EOF_ سنجعل السكربت في الدرس القادم يُظهِر معلومات حقيقة من نظامنا. ترجمة -وبتصرّف- للمقال Here Scripts لصاحبه William Shotts.
  13. قبل أن تبدأ في كتابة سكربتات جديدة، عليّ أن أشير إلى أنَّك تملك بعض السكربتات الموجودة مسبقًا، وضِعَت هذه السكربتات في مجلد المنزل الخاص بك عندما أُنشِئ حسابك، وتُستعمل لضبط سلوك جلسات سطر الأوامر في حاسوبك؛ تستطيع تعديل هذه السكربتات لتغيير بعض الأمور. سنلقِي نظرةً على سكربتَين من هذه السكربتات في هذا الدرس لكي نتعلم بعض المفاهيم الجديدة والمهمة عن الصَدَفة. يُبقي النظام على مجموعة من المعلومات حول جلستك تدعى "البيئة" (environment)، تحتوي البيئة على أشياء مثل المجلدات التي سيتم البحث فيها عن البرمجيات (PATH)، واسم المستخدم، واسم الملف الذي سيُحفَظ فيه بريدك الإلكتروني، وغير ذلك. يمكنك رؤية قائمة كاملة لضبط البيئة بالأمر set. هنالك نوعان من الأوامر التي تحتويها البيئة، وتُعرَف بالاختصارات (aliases) ودوال الصّدفة (shell functions). ما هو منشأ البيئة؟ تبدأ صَدَفة bash عندما تُسجِّل دخولك إلى النظام، وتقرأ سلسلة من ملفات الضبط تُسمى "ملفات بدء التشغيل" أو "ملفات البدء" (startup files) التي تُعرِّف البيئة الافتراضية التي يتشارك فيها جميع المستخدمين؛ ثم ستقرأ ملفات بدء إضافية موجودة في مجلد المنزل الخاص بك التي تُعرِّف بيئتك الشخصية. يختلف الترتيب بحسب نوع جلسة سطر الأوامر التي بدأتها، إذ أنَّ هنالك نوعان: جلسة تحتاج إلى تسجيل دخول (login shell session) وجلسة لا تحتاج إلى تسجيل دخول (non-login shell session). الجلسة التي تحتاج إلى تسجيل دخول هي الجلسة التي تسألك عن اسم المستخدم وكلمة المرور، وذلك عندما تستعمل إحدى الطرفيات الوهمية (virtual console) على سبيل المثال. أما الجلسات التي لا تحتاج إلى تسجيل دخول فهي تحدث عادةً عندما تُشغِّل محاكي الطرفية داخل الواجهة الرسومية. تقرأ الصَدَفة التي تحتاج إلى تسجيل دخول ملف بدء أو أكثر كما هو موضَّح هنا: ‎/etc/profile: سكربت الضبط العام الذي يُطبَّق على جميع المستخدمين. ‎~/.bash_profile: ملف بدء خاص بالمستخدم، يمكن أن يُستعمل لضبط خياراتٍ أخرى غير موجودة في سكربت الضبط العام، أو لتجاوز بعضها وإعادة تعريفها. ‎~/.bash_login: إن لم يكن الملف ‎~/.bash_profile موجودًا فستحاول الصَدَفة bash قراءة هذا السكربت. ‎~/.profile: إن لم يكن الملف ‎~/.bash_profile أو ‎~/.bash_login موجودًا فستحاول الصَدَفة bash قراءة هذا الملف. هذا هو السلوك الافتراضي في التوزيعات المبنية على دبيان مثل أوبنتو. أما الصَدَفة التي لا تحتاج إلى تسجيل دخول، فتقرأ ملفات البدء الآتية: ‎/etc/bash.bashrc: سكربت ضبط عام يُطبَّق على جميع المستخدمين. ‎~/.bashrc: ملف بدء خاص بالمستخدم، يمكن أن يُستعمل لضبط خياراتٍ أخرى غير موجودة في سكربت الضبط العام، أو لتجاوز بعضها وإعادة تعريفها. إضافةً إلى قراءة ملفات الضبط السابقة، ترث الجلساتُ التي لا تحتاج إلى تسجيل دخول البيئةَ من العملية الأب (parent process) التي تكون عادةً جلسة تحتاج إلى تسجيل دخول. ألقِ نظرةً على نظامك لترى ما هي ملفات البدء التي عندك، لكن لاحظ أنَّ أغلبية الملفات السابقة تبدأ بنقطة (مما يعني أنها مخفية)، لذا عليك استخدام الخيار ‎-aمع الأمر ls. ls -a ملف ‎~/.bashrc هو أهم ملف بدء من وجه نظر المستخدم العادي لأنه يُقرَأ دائمًا. حيث تقرأه الجلسات التي لا تحتاج إلى تسجيل دخول افتراضيًا، وأغلبية ملفات البدء الخاصة بالجلسات التي تحتاج إلى تسجيل دخول تقرأ ملف ‎~/.bashrc أيضًا. إذا ألقيت نظرةً داخل ملف ‎.bash_profile‎ (الملف الآتي مأخوذ من توزيعة CentOS)، فسيبدو شبيهًا بالآتي: # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin export PATH تذكَّر أنَّ الأسطر التي تبدأ برمز # هي تعليقات ولا تُفسَّرها الصَدَفة؛ حيث أُضيفت هذه الأسطر لشرح الشيفرة لمن يقرأها من البشر. ستجد في السطر الرابع أول الأشياء المثيرة للاهتمام: if [ -f ~/.bashrc ]; then . ~/.bashrc fi هذه هي عبارة if الشرطية، التي سنشرحها بالتفصيل في درسٍ لاحق، لكنني سأفسرها لك كالآتي: إذا كان الملف ‎~/.bashrc موجودًا، فنفِّذ محتويات ‎~/.bashrc. يمكننا أن نرى أنَّ الشيفرة القصيرة السابقة هي التي تجعل الجلسات التي تحتاج إلى تسجيل الدخول تقرأ محتويات الملف ‎.bashrc. الخطوة التالية في ملف البدء هي ضبط المتغير PATH وإضافة ‎~/bin إلى قائمة المجلدات التي سيتم البحث فيها عن الملفات التنفيذية للأوامر. وفي نهاية الملف: export PATH وظيفة الأمر export هي إخبار الصَدَفة أنَّ عليها جعل محتويات المتغير PATH متاحةً للعمليات التي تنحدر منها (الأبناء). الاختصارات aliases الاختصارات (aliases) هي طريقة سهلة لإنشاء أمر جديد يعمل اختصارًا لأمرٍ أطول. لها الشكل العام الآتي: alias name=value حيث name هو اسم الأمر الجديد و value هي السلسلة النصية التي ستُنفَّذ عند إدخال name في سطر الأوامر. لنُنشِئ اختصارا اسمه l (حرف L صغير) ولنجعله اختصارًا للأمر ls -l (أي عرض محتويات المجلد بالصيغة التفصيلية). تأكَّد أنَّ مجلد العمل الحالي هو المنزل، ثم افتح ملف ‎.bashrc باستخدام محررك النصي المُفضَّل وأضف السطر الآتي إلى نهاية الملف: alias l='ls -l' عند إضافتك للأمر alias إلى الملف، فستُنشِئ أمرًا جديدًا اسمه l الذي يكافئ ls -l. أغلِق جلسة الطرفية الحالية وابدأ واحدة جديدة لتجربة الاختصار التي أنشأناه، وذلك لإعادة قراءة محتويات الملف ‎.bashrc. يمكنك باستخدام هذه التقنية إنشاء أي عدد من الاختصارات المُخصصة لاستعمالك الشخصي، هذه إحداها: alias today='date +"%A, %B %-d, %Y"' سيُنشِئ السطر السابق اختصارا جديدا اسمه today الذي سيُظهِر تاريخ اليوم بتنسيقٍ جميل. بالمناسبة، الأمر alias هو أمر مُضمَّن في الصَدَفة (shell builtin)، أي أنَّك تستطيع إنشاء الأوامر البديلة مباشرةً من سطر الأوامر؛ لكن يجب أن تعلم بأنَّ تلك الأوامر ستزول عند إغلاقك لجلسة الطرفية الحالية. مثال: $ alias l='ls -l' دوال الصدفة ستستفيد من أمر alias عند إنشاء اختصارات لأوامر بسيطة، لكن ماذا لو أردت إنشاء شيءٍ أكثر تعقيدًا؟ عليك حينها أن تجرِّب شيئًا يسمى "دوال الصدفة" (shell functions)، التي يمكنك اعتبارها أنهَّا "سكربتات داخل سكربتات"، أو سكربتات فرعية صغيرة. لنجرب واحدةً منها! افتح ملف ‎.bashrc بمحررك وضع ما يلي بدلًا عن الاختصار today: today() { echo -n "Today's date is: " date +"%A, %B %-d, %Y" } صدِّق أو لا تصدِّق، () هو أمر مضمَّن بالصدفة أيضًا مثَلُهَ كَمَثَلِ الأمر alias، حيث يمكنك أيضًا إدخال دوال الصدفة مباشرةً من سطر الأوامر. $ today() { > echo -n "Today's date is: " > date +"%A, %B %-d, %Y" > } $ لكن تلك الدوال -مثلما هو عليه الحال مع الأمر alias- ستزول عند إغلاق جلسة الطرفية الحالية. ترجمة -وبتصرّف- للمقال Editing The Scripts You Already Have لصاحبه William Shotts.
  14. سنتطرق في هذا المقال إلى كيفية استخدام خاصية script بشكل مبسط في برنامج Photoshop لعمل تأثير تجريدي بسيط وجميل. هذه النتيجة النهائية لما سنتحصل عليه بعد تطبيق كامل خطوات الدرس: افتح مشروعًا جديدًا على Photoshop بالإعدادات التالية: الأبعاد: 1020x768pixels.الدّقة: Resolution 720Dpi.نمط الألوان: Color Mode RVB8bit.نحدد أداة الفرشاة (Brush Tool (B بشعاع 3px: ثم بأداة القلم (Pen Tool (P نرسم الشكل التالي: ثم نضغط على الشكل بزر الفأرة الأيمن ونختار stroke Path: تظهر لنا نافذة نختار من بين القائمة المنسدلة Brush: لنحصل على الشكل: الآن نقوم بإظهار نافدة السكريبت وذلك بالضغط على (Alt+F9): ثم نضغط على الأيقونة المبينة في الصورة لإنشاء Script جديد: للعلم: أي خطوة سنقوم بها الآن ستُسجل في Script وتنفذ أثناء تشغيله مرة أخرى. ننسخ الطبقة المرسومة بأداة القلم سابقا ونضغط الاختصار (Ctrl+T) ثم نميل الشكل قليلا: ثم نوقف السكريبت بالضغط على زر التوقيف: ملاحظة: زر تشغيل Script قد لا يستجيب الحاسوب سريعا ويُظهر بعض البطء حاول أن تمزج الطبقات الناتجة عن Script كلما صادفت ذلك. نشغل Script عدة مرات إلى أن نحصل على هذا الشكل: بعد ذلك، قم بتطبيق خصائص الدمج التالية: نذهب بعدها إلى القائمة: Menu > Filter > Blur > Gaussian Blur ثم نضيف النص الخاص بنا: ثم نغير في خصائص الدمج الخاصة بالنص كما يلي: ننسخ طبقة النص ونطبق عليها فلتر Blur Motion من القائمة: Menu > Filter > Blur > Motion Blur ثم إلى قيمة Lighten في خصائص الدمج: نضيف طبقة جديدة (Ctrl+Shift+N) ثم إلى القائمة: Menu > Filter > Render > Clouds نغير خصائص الدمج إلى قيمة Overlay: لإضفاء بعض الجمالية نضيف دوائرًا على الشكل: نملؤها تدريجيا من الأخضر إلى الأبيض ثم الثانية من الأحمر إلى الأبيض والثالثة من الأزرق إلى الأبيض: ونطبق عليها فلتر Gaussian Blur من القائمة: Menu > Filter > Blur > Gaussian Blur ثم نغير خصائص الدمج إلى قيمة Overlay: لنحصل آخيرا على هذه النتيجة النهائية: ترجمة -وبتصّرف- للمقال: Utilisation des script pour créer un effet abstract avec photoshop cs4.
×
×
  • أضف...