المحتوى عن 'لينكس'.



مزيد من الخيارات

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

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

نوع المُحتوى


التصنيفات

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

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

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

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

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

التصنيفات

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

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

  1. نشرح طريقة تثبيت وإعداد خادم Apache أباتشي على توزيعة أوبنتو، وسنستعمله لتخديم صفحات HTML الخاصة بنا. لتثبيت خادم Nginx راجع فيديو تثبيت وضبط خادم Nginx في أكاديمية حسوب. قسم خوادم الويب في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها.
  2. نشرح طريقة تثبيت وإعداد خادم Nginx على توزيعة أوبنتو، وسنستعمله لتخديم صفحات HTML الخاصة بنا. لتثبيت خادم أباتشي راجع فيديو تثبيت وضبط خادم Apache في أكاديمية حسوب. قسم خوادم الويب في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها.
  3. نشرح طريقة تثبيت وإعداد خادم PostgreSQL على نظام أوبنتو 18.04. مع إعداد كلمة مرور للمستخدم root؛ وإنشاء قاعدة بيانات جديدة ومستخدم جديد لديه الصلاحيات الكاملة عليها. قسم PostgreSQL في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها: https://academy.hsoub.com/devops/servers/databases/postgresql/ نوفر توثيقًا كاملًا لجميع تعليمات SQL على موسوعة حسوب: https://wiki.hsoub.com/SQL
  4. نشرح طريقة تنصيب وإعداد خادم MySQL على نظام أوبنتو 18.04. مع إعداد كلمة مرور للمستخدم root؛ وإنشاء قاعدة بيانات جديدة ومستخدم جديد لديه الصلاحيات الكاملة عليها. نوفر توثيقًا كاملًا لجميع تعليمات SQL على موسوعة حسوب: https://wiki.hsoub.com/SQL
  5. بعد برمجتك لموقعك باستخدام روبي وإطار ريلز، حان الوقت الآن لنشر التطبيق على خادم (server) ليستطيع زوارك الوصول إليه. سنعتمد في هذا الفيديو على أحد التطبيقات الذي طورناه في دورة تعلم تطوير تطبيقات الويب باستخدام روبي: https://academy.hsoub.com/learn/ruby-web-application-development/ مستودع التطبيق: https://github.com/HsoubAcademy/rails-twitter-web-app نوفر في موسوعة حسوب توثيقًا كاملًا للغة روبي وإطار العمل ريلز باللغة العربية: https://wiki.hsoub.com/Ruby https://wiki.hsoub.com/Rails
  6. نشرح طريقة الاتصال الآمنة عبر SSH بخوادم لينكس باستعمال برمجية PuTTY. وهذا يتضمن إعداد الوصول إلى الخادم عبر كلمة المرور، أو عبر مفتاح عام.
  7. لعلك تتساءل عن السبب الذي يجعلنا نستخدم Docker لتثبيت lamp أو lemp في حين أننا نستطيع تثبيتهما يدويًا؟ فتثبيتهما سهل ولا يحتاج إلى الكثير من التعقيد، لماذا نلجأ إلى Docker؟ دعني أجيب عن هذا السؤال، إنّ docker برنامج خفيف ويغنينا عن الحاجة إلى الآلات الوهمية مثل Virtualbox أو Xen أو غيرهما لنختبر أو نثبت أنظمة التشغيل. وفائدته معنا في هذا المقال أننا نستطيع استخدامه لسحب نسخ جاهزة من LAMP أو LEMP لتشغيلها في بضع دقائق، بدلًا من التثبيت اليدوي لأباتشي، ثم قاعدة بيانات مثل MariaDB أو mySQL، ثم PHP. وتحدث هذه الحالة التي تحتاج فيها إلى نسخة جاهزة وسريعة لاختبار شيء ما عليها إن كنت مطورًا أو مختبرًا أو شغوفًا بالبرمجة وتريد أن تختبر تطبيقًا يعمل في الويب، فتجد نفسك في حاجة إلى تثبيت كل تلك الخطوات التي ذكرتها في الفقرة السابقة، ولعلك جربت هذا من قبل ووجدتها عملية مرهقة وطويلة، وهنا تبرز ميزة Docker حيث يمكننا تثبيت وتشغيل برامج جاهزة ومعدة مسبقًا مباشرة دون الحاجة إلى خوض تفاصيلها التقنية كأننا نثبتها لأول مرة بأنفسنا. وهو ما سنشرحه في هذا المقال على LAMP أو LEMP. تثبيت LAMP/LEMP باستخدام Docker دعنا نبحث في docker عن نسخ جاهزة من LAMP أو LEMP: $ sudo docker search lamp وسيكون الخرج مشابهًا لهذا: NAME DESCRIPTION STARS OFFICIAL AUTOMATED reinblau/lamp Dockerfile for PHP-Projects with MySql client 17 [OK] dockie/lamp 6 [OK] nickistre/ubuntu-lamp LAMP server on Ubuntu 4 [OK] nickistre/ubuntu-lamp-wordpress LAMP on Ubuntu with wp-cli installed 4 [OK] nickistre/centos-lamp LAMP on centos setup 3 [OK] damienlagae/lamp Docker LAMP with supervisord 3 [OK] boolean93/lamp LAMP based on linode/lamp 2 [OK] drunomics/lamp 1 [OK] avatao/lamp LAMP base image 1 [OK] nickistre/ubuntu-lamp-xdebug LAMP on Ubuntu with xdebug installed 1 [OK] nickistre/centos-lamp-wordpress LAMP on CentOS setups with wp-cli installed 1 [OK] linuxconfig/lamp Automated build LAMP stack environment for... 1 [OK] greyltc/lamp a super secure, up-to-date and lightweight... 0 [OK] kazaoki/lamp ローカルフォルダをマウントす... 0 [OK] greyltc/lamp-gateone LAMP stack with gateone server & webdav 0 [OK] fauria/lamp Modern, developer friendly LAMP stack. Inc... 0 [OK] drunomics/lamp-memcached LAMP + Memcached base image. 0 [OK] rpawel/lamp Apache 2.4 + php5-fpm container 0 [OK] lioshi/lamp Docker image for LAMP + MySql under debian 0 [OK] nickistre/centos-lamp-xdebug LAMP on centos with xDebug 0 [OK] greyltc/lamp-aur LAMP stack (in Arch with php7) with AUR ac... 0 [OK] alledia/lamp General LAMP for our tests, based on phusi... 0 [OK] greatfox/lamp 0 [OK] cnrk/lamp LAMP stack Docker image. 0 [OK] grmanit/lamp Based on tutum/lamp with additional settin... 0 [OK] وكما ترى من النتيجة أعلاه، فهناك الكثير من نسخ LAMP المتوفرة لتوزيعات آرتش وCent OS وأوبنتو، وهي مرتبة وفق تقييم المستخدمين لها. وبالمثل يمكننا أن نبحث عن LEMP أيضًا: $ sudo docker search lemp ثم اختر نسخة lemp مناسبة لك، سأحمّل أنا مثلًا nickistre/ubuntu-lamp: $ docker pull nickistre/ubuntu-lamp ويكون الخرج مشابهًا لهذا: Using default tag: latest latest: Pulling from nickistre/ubuntu-lamp faecf96fd5ab: Pull complete 995977506e98: Pull complete efb63fb8dcb6: Pull complete a3ed95caeb02: Pull complete 61626f5cc06d: Pull complete d42e54d21590: Pull complete 4a32d1f581a1: Pull complete 52f44a8dd6d0: Pull complete ce6c1074ae9e: Pull complete 2fa559435609: Pull complete 93a433221384: Pull complete 521d09b9a2d1: Pull complete 6222edddc59d: Pull complete 8fa401b50efc: Pull complete 683063a5d5e0: Pull complete 1f87fa5088b3: Pull complete c5ee1c14048f: Pull complete Digest: sha256:e913d43c204b3cdb931156c1a680c712acfe8db531225ec7b9e4708fc7ebe93c Status: Downloaded newer image for nickistre/ubuntu-lamp:latest سيحمّل الأمر أعلاه نسخة LAMP لأوبنتو، يمكنك تحميل نسختك الخاصة لتوزيعتك كما أوضحنا قبل قليل. وإن لم ترغب في تحميل واستخدام النسخ التي يوفرها docker من الطرفية، فيمكنك تحميلها من Docker hub حيث تجد آلاف النسخ المستضافة هناك. اذهب إلى الرابط أعلاه وابحث عن نسخة LAMP التي تريدها وحمّلها. في حالتي أنا، فقد اخترت نسخة nickistre/ubuntu-lamp كما قلت قبل قليل: اضغط على النسخة التي تريد لمعرفة مزيد من البيانات عنها مثل كيفية تثبيتها واستخدامها: ستجد النسخ التي تحملها في مجلد var/lib/docker/، ولسرد تلك النسخ نفذ الأمر التالي: $ docker images مثال للخرج: REPOSITORY TAG IMAGE ID CREATED SIZE nickistre/ubuntu-lamp latest 5e750e4f49e4 2 days ago 633 MB reinblau/lamp latest 2813b461f843 9 days ago 697.9 MB hello-world latest 690ed74de00f 5 months ago 960 B والآن نشغّل النسخة بعد أن حمّلناها: $ docker run -it nickistre/ubuntu-lamp /bin/bash ستجد نفسك قد دخلت بشكل آلي إلى المجلد الجذر للحاوية على الويب كمستخدم جذر: root@184851ac9ebd:/# شغّل خدمة أباتشي: # service apache2 start ثم خدمة MySQL: # service mysql start تأكد ما إن كان خادم أباتشي يعمل أم لا، بفتح هذه الصفحة في متصفحك http://container_IP/. ولكي تجد عنوان IP، اكتب ifconfig أو ip addr في طرفية الحاوية، يجب أن ترى هنا صفحة اختبار خادم أباتشي. ويمكنك معرفة إصدارات أباتشي وMySQL وPHP بهذه الأوامر بالترتيب: # apache2 -v # mysql -v # php -v وهكذا نكون قد ثبتنا LAMP في أوبنتو واستخدمناه، ويمكنك الآن أن تختبر تطبيقك كما كنت تريد، دون أن تشغل بالك بتثبيت كل تلك الحزم يدويًا أو على حاسوبك، حتى لو كان في آلة وهمية. ترجمة -بتصرف- لمقال Deploy LAMP and/or LEMP stacks easily using Docker لصاحبه SK
  8. تعرّفنا في الجزأين السابقيْن من هذا الدليل على كيفية عرض معلومات عن مساحات التخزين وإنشاء مساحات تخزين جديدة وتحجيمها. سنكمل في هذا الجزأ - الأخير من الدليل - ما تعلمناه سابقا ونتعرّف على المهمة الأخيرة من بين المهمّات الأساسية في إدارة التخزين بآلية LVM. تنبيه: تأكّد من أنّ الأجهزة التّي تودّ تطبيق الأوامر المذكورة في هذا الدرس عليها لا تحتوي على بيانات مُهمّة. استخدام هذه الأجهزة مع LVM سيؤدّي إلى الكتابة فوق المحتويات الحاليّة. يُفضَّل أن تختبر الخطوات المعروضة أدناه في آلة افتراضية أو على خادوم خاصّ بأغراض التجربة والاختبار. إزالة أو تقليص مُكوّنات LVM بما أن تقليص مساحة التّخزين قد يؤدي إلى فقدان البيانات، فإجراءات تقليص المساحة المتوفّرة، سواءٌ بتقليص حجم أو حذف المكوّنات، أكثر تعقيدًا من بقية المهامّ. تخفيض حجم وحدة تخزين منطقيّة لتقليص وحدة تخزين منطقيّة، يجب عليك أولا أخذ نسخة احتياطية من بياناتك. فبما أن هذه العمليّة تقلّص مساحة التّخزين المُتوفّرة فإن أي خطأ يُمكن له أن يُؤدي إلى فقدان البيانات. إذا كنت جاهزا، تأكّد من حجم المساحة المُستخدمة حاليّا: df -h المُخرج: Filesystem Size Used Avail Use% Mounted on . . . /dev/mapper/LVMVolGroup-test 4.8G 521M 4.1G 12% /mnt/test في هذا المثال، يبدو بأنّنا نستخدم حاليّا حوالي 521M من المساحة. استعمل هذه المعلومة لتحديد الحجم الذي تريد تقليص وحدة التخزين إليه. تاليّا، أزل تركيب نظام الملفّات. فعلى عكس التوسيعات، يجب عليك تقليص مساحة نظام الملفّات أثناء إزالة التركيب: cd ~ sudo umount /dev/LVMVolGroup/test بعد إزالة التركيب، تأكّد من أن نظام الملفّات في حالة جيّدة. مرّر نوع نظام الملفّات عبر الخيار -t. سنستعمل الخيار -f للتّحقّق من أن كل شيء على ما يرام حتى ولو بدا كذلك: sudo fsck -t ext4 -f /dev/LVMVolGroup/test بعد التّحقّق من سلامة نظام الملفّات، يُمكنك تقليص مساحته باستخدام الأدوات الخاصّة، في حالة Ext4، فالأمر سيكون resize2fs. مرّر الحجم النّهائي لنظام الملفّات. تنبيه: أكثر خيار أمانا هو تمرير حجم نهائي أكبر بكثير من الحجم المُستخدم حاليا. أعط نفسك مساحة أمان لتجنّب فقدان البيانات وتأكّد من إنشاء نسخ احتياطيّة. sudo resize2fs -p /dev/LVMVolGroup/test 3G حالما تنتهي العمليّة، قلّص حجم وحدة التّخزين المنطقيّة عبر تمرير نفس الحجم (3G في هذه الحالة) إلى الأمر lvresize عبر الخيار -L. sudo lvresize -L 3G LVMVolGroup/test ستستقبل تنبيها حول فقدان البيانات، إن كنت جاهزا، فاكتب y للاستمرار. بعد تقليص حجم وحدة التّخزين المنطقيّة، تحقّق من سلامة نظام الملفّات مُجدّدا: sudo fsck -t ext4 -f /dev/LVMVolGroup/test إن سار كلّ شيء على ما يرام، فستستطيع إعادة وصل نظام الملفّات بالأمر المُعتاد: sudo mount /dev/LVMVolGroup/test /mnt/test ينبغي الآن على وحدة التّخزين المنطقيّة أن تُقلّص إلى الحجم المُحدّد. حذف وحدة تخزين منطقيّة إن لم تعد بحاجة إلى وحدة تخزين منطقيّة، يُمكنك حذفها باستعمال الأمر lvremove. أولا، أزل تركيب وحدة التخزين: cd ~ sudo umount /dev/LVMVolGroup/test بعدها، احذف وحدة التخزين بالأمر التّالي: sudo lvremove LVMVolGroup/test سيُطلب منك تأكيد العمليّة، إن كنت متأكّدا من رغبتك في حذف وحدة التّخزين، فاكتب y. حذف مجموعة تخزين لحذف مجموعة تخزين كاملة، بما في ذلك جميع وحدات التّخزين المنطقيّة المتواجدة بها، استعمل الأمر vgremove. قبل حذف مجموعة تخزين، عليك حذف وحدات التّخزين بداخلها بالعمليّة أعلاه. أو على الأقل، تأكّد من إزالة تركيب جميع وحدات التّخزين بداخل المجموعة: sudo umount /dev/LVMVolGroup/www sudo umount /dev/LVMVolGroup/projects sudo umount /dev/LVMVolGroup/db بعدها يُمكنك حذف مجموعة التّخزين عبر تمرير اسمها إلى الأمر vgremove: sudo vgremove LVMVolGroup سيُطلب منك تأكيد عمليّة حذف المجموعة. إذا كانت هناك أية وحدات تخزين منطقيّة مُتبقيّة، ستُسأل عن تأكيد حذفها واحدة واحدة قبل حذف المجموعة. حذف وحدة تخزين ماديّة إن أردت إزالة وحدة تخزين ماديّة من إدارة LVM، فسيعتمد الإجراء المطلوب على ما إذا كانت الوحدة مُستخدمة من طرف LVM أو لا. إن كانت وحدة التّخزين الماديّة مُستخدَمة، سيتوجّب عليك نقل المداءات الماديّة على الجهاز إلى مكان آخر. سيتطلّب ذلك وجود وحدات تخزين ماديّة أخرى لتحتضن المداءات الماديّة. إن كنت تستعمل أنواعا مُعقّدة من وحدات التّخزين المنطقيّة، فقد يتوجّب عليك الحصول على المزيد من وحدات التّخزين الماديّة حتى ولو كانت لديك مساحة تخزين كافيّة. إن كان لديك عدد كاف من وحدات التّخزين الماديّة في مجموعة التّخزين لاحتضان المداءات الماديّة، فانقلها إلى خارج وحدة التّخزين الماديّة التي ترغب في إزالتها عبر كتابة ما يلي: sudo pvmove /dev/sda يُمكن لهذه العمليّة أن تأخذ وقتا طويلا حسب حجم وحدات التّخزين وكميّة البيانات التي يتوجب نقلها. حالما تنتقل المداءات إلى وحدات تخزين أخرى، يُمكنك حذف وحدة التّخزين الماديّة من مجموعة التّخزين عبر الأمر التّالي: sudo vgreduce LVMVolGroup /dev/sda هذه العمليّة كفيلة بإزالة وحدات التّخزين التي أُخلِيت من مجموعة التّخزين. بعد انتهاء العمليّة، يُمكنك حذف علامة وحدة التّخزين الماديّة من جهاز التّخزين عبر الأمر: sudo pvremove /dev/sda ينبغي الآن أن تتمكّن من استعمال جهاز التّخزين المُزال لأغراض أخرى أو إزالته من النّظام بالكامل. ختاما إلى هذه النّقطة، يجب أن يكون لديك فهم لكيفيّة إدارة أجهزة التّخزين على أوبونتو 16.04 مع LVM. يجب أن تعرف كيفيّة الحصول على معلومات عن مكوّنات LVM، كيفيّة استخدام LVM لتركيب نظام تخزين خاص بك، وكيفيّة تعديل وحدات التّخزين لتلبيّة حاجاتك. يُمكنك اختبار هذه المبادئ في بيئة آمنة لفهم أعمق حول آليّة عمل LVM ومكوّناته. ترجمة – بتصرّف - للمقال How To Use LVM To Manage Storage Devices on Ubuntu 16.04 لكاتبه Justin Ellingwood.
  9. بعد أن تعرّفنا في الجزء السابق على كيفية عرض معلومات عن مختلف العناصر في LVM، سنتطرّق في هذا الجزء من الدليل إلى كيفية التحكم في هذه المكوّنات بإنشاء مكوّنات جديدة أو إعادة تحجيم (توسيع أو تقليص) مكوّنات موجودة. إنشاء أو توسيع مكوّنات LVM سنتحدّث في هذه الفقرات عن كيفيّة إنشاء وتوسيع وحدات التّخزين الماديّة والمنطقيّة وكذا مجموعات التّخزين. إنشاء وحدات تخزين ماديّة من أجهزة تخزين خام لاستعمال أجهزة التّخزين مع LVM، يجب عليها أولا أن تُعلّم على أنها وحدات تخزين ماديّة. ما يُحدّد إمكانيّة استخدام الجهاز داخل مجموعة تخزين. أولا، استعمل الأمر lvmdiskscan لإيجاد جميع أجهزة التّخزين التي يُمكن لـLVM رؤيتها واستخدامها: sudo lvmdiskscan المُخرج: /dev/ram0 [ 64.00 MiB] /dev/sda [ 200.00 GiB] /dev/ram1 [ 64.00 MiB] . . . /dev/ram15 [ 64.00 MiB] /dev/sdb [ 100.00 GiB] 2 disks 17 partitions 0 LVM physical volume whole disks 0 LVM physical volumes في المُخرج أعلاه، بتجاهل أجهزة /dev/ram*، يُمكننا رؤية الأجهزة التّي يُمكن تحويلها إلى وحدات تخزين ماديّة لـLVM. تنبيه: تأكّد من أنّ الأجهزة التّي ترغب باستعمالها مع LVM لا تحتوي على أيّة بيانات مُهمّة. استخدام هذه الأجهزة مع LVM سيؤدّي إلى الكتابة فوق المحتويات الحاليّة. إذا كنت تمتلك بيانات مهمّة على خادومك فأنشئ نسخا احتياطية قبل الاستمرار في تطبيق الدّرس. لجعل أجهزة التّخزين وحدات تخزين ماديّة خاصّة بـLVM، استعمل الأمر pvcreate. يُمكنك تمرير عدّة أجهزة في نفس الوقت: sudo pvcreate /dev/sda /dev/sdb هذا الأمر سيكتب ترويسة LVM على جميع الأجهزة الهدف لتخصيصها كوحدات تخزين LVM ماديّة. إنشاء مجموعة تخزين من وحدات التّخزين الماديّة لإنشاء مجموعة تخزين جديدة من وحدات التّخزين الماديّة، استعمل الأمر vgcreate. سيتوجّب عليك تمرير اسم للمجموعة متبوعا بوحدة تخزين ماديّة واحدة على الأقل: sudo vgcreate volume_group_name /dev/sda استبدل volume_group_name باسم من اختيارك لمجموعة التّخزين. سينشئ المثال أعلاه مجموعة تخزين انطلاقا من وحدة تخزين ماديّة واحدة فقط. يُمكنك تمرير أكثر من وحدة تخزين ماديّة عند إنشاء المجموعة إن أردت ذلك: sudo vgcreate volume_group_name /dev/sda /dev/sdb /dev/sdc عادة ستحتاج إلى مجموعة تخزين واحدة فقط لكل خادوم. بحيث يُمكنك إضافة أي مساحة تخزين إضافيّة لمنطقة مُوحّدة ثمّ تخصيص وحدات تخزين منطقيّة منها. الحاجة إلى استخدام أحجام مداءات مُختلفة من الأسباب التّي قد تدفعك إلى إنشاء أكثر من مجموعة تخزين واحدة. في العادة، لن يتوجّب عليك تحديد حجم المدى (الحجم المبدئي هو 4M ويُعدّ كافيّا لمُعظم الاستخدامات)، لكنّ إن أردت، يُمكنك تحديد حجم المداءات عند إنشاء مجموعة التّخزين باستعمال الخيار -s: sudo vgcreate -s 8M volume_group_name /dev/sda سينشئ هذا الأمر مجموعة تخزين مع حجم مداءات يُساوي 8M. إضافة وحدة تخزين ماديّة إلى مجموعة تخزين موجودة مُسبقا لتوسيع مجموعة تخزين عبر إضافة وحدات تخزين ماديّة، استخدم الأمر vgextend. يأخذ هذا الأمر مجموعة تخزين متبوعة بوحدات التّخزين الماديّة التّي ترغب بإضافتها إلى المجموعة. يُمكنك كذلك تمرير أكثر من جهاز في نفس الوقت إن أردت: sudo vgextend volume_group_name /dev/sdb ستُضاف وحدة التّخزين الماديّة إلى مجموعة التّخزين موسّعة بذلك مساحة التّخزين المُتوفّرة على المجموعة. إنشاء وحدة تخزين منطقيّة بحجم مُحدّد لإنشاء وحدة تخزين منطقيّة من مجموعة تخزين، استعمل الأمر lvcreate. حدّد حجم وحدة التّخزين المنطقيّة باستخدام الخيار -L، وحدّد اسما عبر الخيار -n، ومرّر مجموعة التّخزين الأم. على سبيل المثال، لإنشاء وحدة تخزين منطقيّة تُسمّى test من مجموعة تخزين تُسمّى LVMVolGroup، اكتب: sudo lvcreate -L 10G -n test LVMVolGroup على افتراض أنّ بمجموعة التّخزين مساحة تخزين فارغة توافق حجم وحدة التّخزين، فإنشاء وحدة التّخزين الجديدة سيتمّ بنجاح. إنشاء وحدة تخزين منطقيّة من كامل باقي المساحة الفارغة إن أردت إنشاء وحدة تخزين من باقي المساحة الفارغة على مجموعة تخزين، استعمل الأمر vgcreate مع الخيار -n لتحديد اسم لها ثمّ مرّر مجموعة التّخزين كما في السّابق. عوضا عن تمرير حجم مُعيّن، استعمل الخيار -l 100%FREE لتحديد بقيّة المساحة الفارغة في المجموعة: sudo lvcreate -l 100%FREE -n test2 LVMVolGroup إنشاء وحدات تخزين منطقيّة مع خيارات مُتقدّمة يُمكنك إنشاء وحدات تخزين منطقيّة مع خيارات مُتقدّمة كذلك. التّالي بعض من الخيارات التي يُمكن أن تأخذها بعين الاعتبار: --type: يقوم هذا الخيار بتحديد نوع وحدة التّخزين المنطقيّة ما يُحدّد كيفيّة تخصيص مساحة له. بعض من هذه الأنواع لن تكون مُتوفّرة إن لم يكن لديك الحدّ الأدنى من وحدات التّخزين الماديّة التي يتطلّبها النّوع. بعض من أكثر هذه الأنواع شيوعا هي كما يلي: linear: النّوع المبدئي. أجهزة التّخزين المُستخدمة ستُضاف بعضها على بعض واحدا تلو الآخر. striped: مُشابه لـRAID 0، تُقسّم البيانات إلى قطع صغيرة وتُنشر على شكل قوس على وحدات التّخزين الماديّة المُستعملة. ما يؤدّي إلى تحسينات في الأداء، لكن يُمكن أن يؤدي إلى زيادة في قابليّة إصابة البيانات. لتحديد هذا النّوع، يجب عليك تمرير الخيار -i ويتطلّب وحدتي تخزين ماديّتين على الأقل. raid1: إنشاء وحدة تخزين RAID 1 مُنعكسة Mirrored. مبدئيًّا، سيكون للانعكاس نُسختان، لكن يُمكنك تحديد عدد أكبر عبر الخيار -m المشروح أسفله. هذا الخيار يتطلّب وحدتي تخزين ماديّتين على الأقل. raid5: إنشاء وحدة تخزين RAID 5. يتطلّب ثلاثة وحدات تخزين ماديّة على الأقل. raid6: إنشاء وحدة تخزين RAID 6. يتطلّب أربعة وحدات تخزين ماديّة على الأقل. -m: يحدّد عدد نُسخ البيانات الإضافيّة. إن مرّرت القيمة 1 فهذا يعني بأنّ نُسخة واحدة إضافيّة من البيانات ستُصان، بحيث يكون لديك مجموعتان من نفس البيانات. -i: يُحدّد عدد الشّرائط Stripes. هذا الخيار مطلوب للنوع striped، ويُمكن أن يُؤثّر على بعض خيارات RAID الأخرى. -s: يُحدّد بأنّ أخذ لقطة يجب أن يتمّ على مُستوى وحدة التّخزين المنطقيّة الحاليّة عوضا عن إنشاء وحدة تخزين منطقيّة جديدة ومُستقلّة. سنلقي نظرة على بضعة أمثلة لهذه الخيارات لنرى حالات الاستخدام الشّائعة. لإنشاء وحدة تخزين شريطيّة Striped volume، يجب عليك تحديد شريطين على الأقل. هذه العمليّة تحتاج إلى وحدتي تخزين ماديّتين على الأقل مع مساحة تخزين متوافقة مع الحجم المُراد: sudo lvcreate --type striped -i 2 -L 10G -n striped_vol LVMVolGroup لإنشاء مساحة تخزين مُنعكسة Mirrored volume، استخدم النّوع raid1. إن أردت أكثر من مجموعتي بيانات، استعمل الخيار -m. المثال التّالي يستعمل -m 2 لإنشاء ثلاث مجموعات من البيانات (يعتبر LVM بأنّها مجموعة واحدة من البيانات مع انعكاسين). ستحتاج إلى ثلاثة وحدات تخزين ماديّة على الأقل لنجاح العمليّة: sudo lvcreate --type raid1 -m 2 -L 20G -n mirrored_vol LVMVolGroup لإنشاء لقطة لوحدة تخزين ما، يجب عليك تحديد وحدة التّخزين المنطقيّة الأصل التي ستأخذ منها اللقطة وليس كامل مجموعة التّخزين. لا تحجز اللقطات الكثير من المساحة في البدء، لكنّ حجمها يزداد كلّما أُجرِيَت تغييرات على وحدة التّخزين المنطقيّة الأصليّة. عند إنشاء لقطة ما، فالحجم المُخصّص يكون أقصى حدّ يُمكن للقطة أن تصل إليه (اللقطات التي تزيد عن هذا الحجم مُعطّلة وغير قابلة للاستخدام؛ لكن يُمكن توسيع اللقطات التي تقترب من هذا الحجم): sudo lvcreate -s -L 10G -n snap_test LVMVolGroup/test تنبيه: لإعادة وحدة تخزين إلى الحالة التي تتواجد بها اللقطة، استخدم الأمر lvconvert --merge: sudo lvconvert --merge LVMVolGroup/snap_test سيقوم هذا الأمر بإعادة اللقطة إلى الحالة التي كانت عليها عندما تمّ إنشاؤها. كما ترى، هناك العديد من الخيارات التي يُمكن لها أن تُغيّر طريقة عمل وحدة التخزين المنطقيّة بشكل كبير. زيادة حجم وحدة تخزين منطقيّة المرونة في التّعامل مع وحدات التّخزين المنطقيّة من أكثر المميّزات المتوفّرة في LVM. إذ يُمكنك بسهولة تعديل عدد أو حجم وحدات التّخزين المنطقيّة دون إيقاف النّظام. لزيادة حجم وحدة تخزين منطقيّة أنشئت مُسبقا، استعمل الأمر lvresize. مرّر قيمة إلى الخيار -L لتحديد حجم جديد. يُمكنك كذلك استخدام أحجام نسبيّة عبر الرّمز +. في هذه الحالة سيقوم LVM بإضافة الكميّة المُحدّدة إلى الحجم الكلي لوحدة التّخزين. لتعديل حجم نظام الملفّات المُستخدم على وحدة التّخزين بشكل آلي، استعمل الخيار --resizefs. لتحديد اسم صحيح لوحدة التّخزين التي ترغب بتوسيعها، سيتوجّب عليك تحديد مجموعة التّخزين، ثمّ رمز / متبوعا باسم وحدة التّخزين المنطقيّة: sudo lvresize -L +5G --resizefs LVMVolGroup/test في هذا المثال، سيتمّ زيادة 5G لكل من وحدة التّخزين test ونظام الملفّات المُستخدم. إن أردت توسيع نظام الملفّات يدويًّا، يُمكنك حذف الخيار --resizefs واستعمال أداة توسيع نظام الملفّات الخاصّة. مثلا، لو كان نظام الملفّات هو Ext4 فيُمكن أن تكتب: sudo lvresize -L +5G LVMVolGroup/test sudo resize2fs /dev/LVMVolGroup/test سيكون لهذه العمليّة نفس تأثير ما سبق. ترجمة – بتصرّف - للمقال How To Use LVM To Manage Storage Devices on Ubuntu 16.04 لكاتبه Justin Ellingwood.
  10. Vagrant هو برنامج يُمكّنك من إنشاء وإعداد بيئات عمل خفيفة للتطوير عليها عن طريق تشغيل آلة وهمية. لماذا أستعمل Vagrant إذا كنت مطور ويب فسيساعدك البرنامج على محاكاة بيئة الخادوم عن طريق تنصيب إحدى نسخ لينكس للخواديم على جهازك. كما يساعدك أيضًا على تجربة تطبيقات الويب خاصتك بدون خوف من الخطأ أو الخوف على جهازك. وإذا كنت تعمل ضمن فريق عمل فإنه سيجعل من العمل أسهل بجعل بيئات التطوير واحدة بنفس البرمجيات والأنظمة. البدء في استعمال Vagrant قبل البدء يجب أن يكون لديك برنامج للآلات الوهمية مثبت ويفضل أن يكون Virtualbox. سيأتي ذكر كيفية ربطه مع برامج أخرى في آخر المقالة. بعد تثبيت Virtualbox يمكنك تثبيت النسخة المناسبة من Vagrant من هنا. أنشأ مجلدًا جديدًا لبيئة العمل خاصتك. وادخل إليه من الطرفية عن طريق الأمر: $ cd myfirst_project_dir ثم اكتب الأمر التالي: $ vagrant init ubuntu/trusty32 ستلاحظ أنه وفي أول مرة فقط بدأ بتحميل الملفات الخاصة بهذه الآلة وستلحظ أيضًا إنشاء ملف في هذا المجلد باسم Vagrantfile. بعد الانتهاء من التحميل قم بتشغيل الآلة الوهمية عن طريق الأمر التالي مع التأكد أنك ما زلت في نفس المجلد : $ vagrant up انتظر قليلًا، بعد الانتهاء، مبارك لك تم تشغيل نظام أوبنتو 14.04 للخادم. بدأ العمل يمكنك الآن للتحكم في النظام كتابة الأمر التالي : $ vargant ssh وسيتم الدخول إلى جلسة الطرفية عن طريق بروتوكول SSH . يمكنك الآن كتابة أوامر لنظام أوبنتو كما تشاء. يمكنك لتثبيت حزمة LAMP $ sudo apt-get install lamp-server^ يمكنك تثبيت أي برامج أو تطبيقات عن طريق سطر الأوامر يمكنك إذا أردت تثبيت Ngnix الاطلاع على هذا الدرس اتبع الإرشادات الخاصة بأوبنتو لأن الصندوق الذي استعملناه هو الخاص بأوبنتو (كما سيأتي لاحقًا في شرح الصناديق). يمكنك أيضًا تثبيت phpmyadmin كما يشرح الدرس لتالي. المجلدات المشتركة انتهيت من إعداد بيئة العمل تريد الآن البدأ في البرمجة ولكن هل ستضطر للدخول إلى جلسة الطرفية هذه كل مرة والعمل عن طريق محررات نصية كـ vim كي تستطيع العمل؟؟ الإجابة هي لا ففي الحقيقة المجلد الذي مساره داخل البيئة الوهمية /vagrant هو نفسه المجلد الذي أنشأت فيه الآلة في البداية أي المجلد الذي يتواجد بداخله ملفVagrantfile. ولتتأكد من كلامي هذا أنشأ في المجلد الحالي ملفًا نصيًا اسمه foo.txt ثم ادخل الآن إلى جلسة الطرفية الخاصة بالآلة الوهمية واكتب : $ cd /vagrant $ ls ستفاجئ بوجود الملف الذي أنشأته سابقًا وبهذا يمكننا Vagrant من العمل على المحررات التي نفضلها من واجهتنا الرسومية ومشاركة كل ما نعمله مع الآلة الضيف. يمكنك أيضًالمشاركة مجلدات أخرى غير هذا المجلد كتابة الآتي داخلVagrantfile : config.vm.synced_folder "src/", "/srv/website" حيث أن المسار الأول هو مسار المجلد الذي تريد مشاركته على آلتك المضيفة والمسار الثاني هو مسار المجلد الموجود في الآلة الوهمية. تهيئة الشبكة الآن بعد تثبيت apache مع حزمة LAMP تريد تصفح الموقع المتواجد على الخادوم على الآلة الضيف من على متصفحك من جهازك فكيف تفعل هذا. يمكنك فعل هذا بتعديل ملف Vagrantfile بحيث سيشبه الآتي : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty32" config.vm.network :forwarded_port, guest: 80, host: 4567 end اكتب الأمر التالي في حاسوبك (ليس بداخل الآلة الوهمية) داخل مجلد الآلة الوهمية: $ vagrant reload الآن يمكنك تصفح موقعك من على الرابط التالي http://127.0.0.1:4567 داخل متصفحك. جعل المجلد الافتراضي لـapache في/vagrant أنت الآن تريد إضافة ملفات البرمجة الخاصة بك وبدأت العمل عليها في المُجلّد/vagrant ولكن لا تزال هناك مشكلة فـapache يحدد المُجلّد /var/www/htmlكمُجلّد افتراضي توجد عليه الملفات التي سوف تمثل واجهة الموقع لذا علينا أن نجعل المُجلّد الافتراضي هو /vagrant/my_awesome_project والذي ستضع عليه ملفات الـPHP الخاصة بمشروعك. في البداية أنشئ في المُجلّد الذي تتواجد فيه الآلة الافتراضية مُجلّدًا فرعيًا وسمه my_awesome_project ثم اكتب الأمر التالي في جلسة الطرفية للآلة الضيف: $ sudo nano /etc/apache2/sites-available/000-default.conf أضف الآتي: DocumentRoot /vagrant/my_awesome_project احفظ التغييرات عن طريق الضغط على Ctrl + X ثم اكتب الأمر التالي: $ sudo nano /etc/apache2/apache2.conf أضف الآتي: <Directory /vagrant> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> احفظه عن طريق الضغط على Ctrl + X ثم اكتب الأمر التالي لإعادة تشغيل الخادوم والعمل بالتغييرات : sudo service apache2 restart مبارك لك الآن يمكنك الدخول إلى المُجلّد الذي يحتوي الآلة الوهمية والدخول إلى المُجلّد المسمى my_awesome_project بداخله وبدأ العمل ومشاهدة التغييرات مباشرة على: http://127.0.0.1:4567 إغلاق الآلة بعد الإنتهاء من العمل سيتوجب عليك إغلاق الآلة الوهمية ويمكن هذا بواحد من ثلاث أوامر داخل دليل الآلة: $ vagrant suspend $ vagrant halt $ vagrant destroy الأمر الأول يقوم بحفظ حالة الآلة كما هي وعند الإقلاع مرة أخرى بالأمرvargant up يكون الإقلاع سريعًا لأنه فقط يقوم بإيقاظ الآلة. الأمر الثاني يعمل على إغلاق الآلة بالكامل وإغلاق كافة البرامج التي كانت تعمل على الآلة وأيضًا يتم الإقلاع مرة أخرى بالأمر vagrant up . الأمر الثالث يمحو الآلة مع كل شيء داخل المجلد الذي يحتويها. الصناديق (Boxes) يستعمل Vagrant الصناديق بدلًا من ترجمة ملفات الآلة الوهمية من الصفر مما يؤدي إلى ضياع الكثير. تعتبر الصناديق كالأنظمة والإعدادات معها المجهزة مسبقًا كي يتم استعمالها مباشرة. يعد الأمر الآتي الذي استعملناه في أول الدرس مثالًا على استخدام أحد الصناديق : $ vagrant init ubuntu/trusty32 والذي من المفترض أن ينشئ آلة وهمية في المجلد الحالي اتخدامًا للصناديق فقد استعمل الصندوق المسمى بـubuntu/trusty32 حالما يتم تنزيل الصندوق يمكنك استعماله في أي مكان وفي أي آلة تنشؤها ويمكنك إضافة أي صندوق جديد عن طريق الأمر التالي: $ vagrant box add box_name وفائدة هذه الصناديق هي استعمال إعدادات وأنظمة جاهزة ومختلفة فمثلًا إذا أردت استعمال CentOS بدلًا من أوبونتو يمكنك استبدال اسم الصندوق بـdanmikita/centos . يمكنك البحث عن الصناديق المتوفرة وأسمائها من خلال الرابط التالي: https://atlas.hashicorp.com/boxes/search التّجهيز (Provisioning) يمكنك التّجهز (Provisioning) من تنفيذ أوامر معينة على الآلة الوهمية بدون الدخول إليها ويمكن ذلك عن طريق التعديل في ملف Vagrantfile وذلك يمكنك من استعمال نفس البرامج والإعدادات على جميع الآلات. لتتمكن من استعمال التزويد عليك إضافة الأمر التالي إلى ملف Vagrantfile لـ: config.vm.provision :shell, path: "bootstrap.sh" هذا الأمر يجعل من ملف bootstrap.sh ملفًا يعمل عند تشغيل الآلة. هناك مجموعة كبيرة أخرى من الأوامر يمكنك الاطلاع عليها من التوثيق الرسمي للبرنامج. يمكنك تفعيل التزويد في الآلة التي تعمل الآن عن طريق الأمر التالي: vagrant reload --provision تغيير Virtualbox يمكنك بكل بساطة استعمال أي برنامج محاكاة مدعوم كـبرنامج VMware على سبيل المثال عن طريق الأمر التالي مع أمر vagrant up: $ vagrant up --provider=vmware_fusion مشاركة الآلة يمكنك مشاركة الآلة خاصتك مع فريق العمل وجعلهم يتمكنون من مراقبتها أو التحكم بها من أي مكان. هناك ثلاثة طرق للمشاركة: مشاركة HTTP ويشارك هذا الآلة عبر منفذ HTTP ويمكن عمل هذا عبر تنفيذ الأمر vagrant share وبعد ذلك وبعد انتهاء الأمر سيظهر في آخره رابطًا يمكنك مشاركته مع فريق عملك. مشاركة SSH يمكن هذا عن طريق كتابة الأمر: vagrant share --ssh سيطلب منك هذا الأمر كتابة كلمة السر التي سيتم التأكد بها من المتصل. بعد الانتهاء من الأمر يمكنك التوصل إلى الآلة من حاسوب آخر عن طريق الأمر: vagrant connect --ssh NAME حيث NAME اسم الآلة الذي ظهر عند نهاية أمر vagrant share --ssh مشاركة عامة وهي تشارك جميع المنافذ الممكنة ويكون ذلك عن طريق الأمرvagrant share ثم كتابة الأمر vagrant connect NAME على الجهاز المتحكم حيث NAME هو اسم الآلة الذي يظهر في نهاية تنفيذ الأمر vagrant share . الخاتمة يمكنك إنشاء أي عدد من الآلات في مُجلّدات مختلفة والعمل عليها جميعًا أو على واحدة منها واستعمال أي صناديق تريد معها وإضافة إعدادات معينة للتزويد ونشرها مع فريق العمل ليتسنى لهم ضبط آلتهم كما هو عندك ومشاركة آلتك عن بعد كي يتحكم جميع فريق العمل في آلة واحدة . المراجع https://docs.vagrantup.com/v2/ http://stackoverflow.com/questions/5891802/how-do-i-change-the-root-directory-of-an-apache-server https://help.ubuntu.com/community/ApacheMySQLPHP
  11. تتطلب الشهادات المتخصصة فهما عميقا ومعرفة جيّدة بمجال الشهادة والمهارات الضرورية لإنجاز الأعمال المرتبطة به. فهي تثبت امتلاك صاحبها للمعرفة والمهارات التي يبحث عنها المشغِّل من أجل اكتتاب موظّف قادر على البدء بالعمل في أقل وقت. إضافة إلى ذلك، تسوّق الشركات شهاداتِ موظفيها للزبناء لتتميّز عن المنافسين، وهو نفس السبب الذي يدفع المتخصّصين لنيل شهادات تميّزهم أثناء التقدم للعمل عن البقية؛ أو عن أقرانهم للحصول على فرص وظيفية أكبر. على مستوى شخصيّ، فإن التحضير والاستعداد لنيل الشهادة المتخصّصة - أو للمحافظة عليها - يجعل المتقدّم على اطّلاع مستمر بموضوع الشهادة ويساعده على اكتساب مهارات جديدة قد لا تكون متاحة له بطرق أخرى. لا يعدّ نظام تشغيل لينكس بدعا من المجالات التقنية الأخرى، بل إن الشعبية المتزايدة التي يحظى بها وسيطرته على غالبية الخواديم العاملة على الشبكة وفي النظم الداخلية للمؤسسات بمختلف أحجامها ومجالاتها؛ إضافة لرغبة الشركات في توظيف أشخاص قادرين على تولي مهمة إدارة الخواديم العاملة بلينكس افتراضيةً كانت أو حقيقة، بكفاءة وفعالية؛ يجعل نيل شهادة متخصصة أمرا مرغوبا إن لم يكن مشروطا في كثير من إعلانات الوظائف. يتوفّر سوق لينكس على الكثير من الشهادات المتخصّصة لتختار بينها سواء كان السبب الذي يدعوك للحصول على الشهادة فرصة وظيفية أفضل أو تأكيد معلوماتك وتحديثها. تختلف شهادات لينكس باختلاف الجهة التي تقف وراءها؛ فمنها الشهادة المتخصّصة في توزيعة واحدة ومنها الشهادات التي لا تعتمد على توزيعة معيّنة. هذه الأخيرة هي التي سنتحدث عنها في هذا المقال. شهادة CompTIA Linux+ Powered by LPI تتميّز منظمة CompTIA غير الربحية بتقديمها للكثير من الشهادات التقنية المتخصّصة بالتعاون مع منظمات ومعاهد تركّز على مجالات محدّدة. تدخل شهادة CompTIA Linux+ Powered by LPI في هذا الإطار إذ تتعاون المنظمة مع معهد Linux Professional Institute, LPI لتقديم شهادة متخصّصة في إدارة أنظمة لينكس. في الأصل كانت المنظمة تقدّم منفردة هذه الشهادة باسم +CompTIA Linux قبل أن يتغير اسمها ابتداءً من سنة 2010 إلى CompTIA Linux+ Powered by LPI بعد التعاون مع معهد LPI. يتطلب الحصول على الشهادة النجاح في اختبارين. يغطّي الأول بنية النظام، تثبيت الحزم Packages وإدارتها، أوامر لينكس ويونكس، الأجهزة الطرفية Devices، أنظمة الملفات File systems والبنية الشجرية المعيارية لأنظمة الملفات في لينكس. أما الثاني فيتناول برمجة Shell، إدارة البيانات، واجهات المستخدم وأسطح المكاتب Desktops، الأنشطة والأشغال الإدارية الأساسية، خدمات النظام القاعدية، أساسيات الشبكات ومواضيع متعلقة بالحماية. تعدّ شهادة CompTIA Linux+ Powered by LPI من الشهادات ذات المستوى الأول Entry level، كما أنها لا تركّز على توزيعة واحدة، بل على نظام التشغيل عموما. يُقدَّر أن المترشح يحتاج لخبرة سنة في إدارة أنظمة لينكس حتى ينال الشهادة. يحوي كل اختبار 60 سؤالا ويدوم 90 دقيقة. ينبغي الحصول على درجة لا تقل عن 500 (من أصل 800) نقطة للنجاح في الاختبار. يبلغ سعر كل اختبار 194 دولارا مع اختلاف حسب المناطق. شهادات LPIC يقدّم هذه الشهاداتِ معهدُ LPI السابق الذكر. وهو معهد غير ربحي متخصّص في تقديم شهادات لينكس غير مرتبطة بتوزيعة معيّنة. أنشئ المعهد سنة 1999 وأصبح في ظرف سنوات من المؤسسات المتميّزة في تقديم شهادات حول لينكس وتقنياته. تُعرف شهادات المعهد بشهادات LPIC (اختصار لـLPI Certification)، وتأتي على مستويات: 1. شهادة Linux Essentials وتُعنى بأساسيات لينكس مثل كتابة سكربتات سهلة وتنفيذها، إرجاع الأرشيف والملفات المضغوطة، العمل على سطر الأوامر، قواعد نظام تشغيل لينكس، البرمجيات الحرة ومفتوحة المصدر FOSS، المستخدمين والمجموعات وأذون الملفات. تتوجّه شهادة Linux Essentials للمبتدئين في عالم لينكس والمتخصصين في مجالات تقنية أخرى ممن يحتاج عملهم للتعامل مع لينكس. لا ترتبط صلاحية هذه الشهادة بمدة زمنية محدّدة. 2. شهادة LPIC-1 وهي الشهادة الأولى ضمن برنامج معهد LPI متعدد المستويات، ولا يُشترط في المتقدم الحصول على شهادة سابقة وإن كانت شهادة Linux Essentials منصوحا بها. تُسمى شهادة LPIC من المستوى الأول بشهادة محترف خواديم لينكس Linux Server Professional Certification. يُطلب من المترشح تجاوز اختبارين يتناولان أساسيات إدارة أنظمة لينكس مثل العمل على سطر الأوامر، إجراء عمليات الصيانة الأساسية، تثبيت نظام التشغيل وإعداده بما في ذلك ضبط سطح المكتب وإعداد الاتصال بشبكة محلية LAN أو شبكة الإنترنت. يمكن للمترشح الحصول على شهادة LPIC-1 بحصوله على شهادة CompTIA Linux+ Powered by LPI، أي أنه يمكن له الحصول على الشهادتين في نفس الوقت بحصوله على شهادة CompTIA. كما أن بمقدور الحاصل على شهادة LPIC-1 نيل شهادة SUSE Certified Linux Administrator التي تقدّمها توزيعة SUSE. يعني هذا أنه بنيل شهادة CompTIA يمكن الحصول على ثلاث شهادات معا بسبب الشراكة بين المنظمات الثلاث. يمكن إجراء اختباري الشهادة بإحدى اللغات التالية: الإنكليزية، الألمانية، الإيطالية، البرتغالية، الإسبانية، الصينية واليابانية. 3. شهادة LPIC-2 الشهادة الثانية ضمن برنامج LPI للشهادات هي Linux Network Professional Certification (شهادة محترف شبكات لينكس)، وهي شهادة متقدّمة يُشترَط أن يكون لدى المترشح لها شهادةُ LPIC-1 السابقة. يتطلب الحصول على الشهادة تجاوز اختبارين: يتناول الأول نواة لينكس، بدء تشغيل النظام، نظام الملفات والأجهزة الطرفية، الإدارة المتقدمة لوسائط التخزين، إعداد الشبكات، صيانة النظام والتخطيط للتوسع؛ أما الاختبار الثاني فيحوي مواضيع مثل خدمات الويب، تشارك الملفات، إدارة عملاء الشبكة، خدمات البريد، أمن النظام، البحث عن المشاكل وإصلاحها وخواديم أسماء النطاقات DNS. تتوجّه شهادة LPIC-2 إلى مديري الأنظمة في المؤسسات الصغيرة والمتوسطة. اللغات المستخدمة في الاختبار هي: الإنكليزية، الألمانية، البرتغالية واليابانية. 4. شهادة LPIC-3 شهادة محترف مشاريع لينكس Linux Enterprise Professional Certification هي الشهادة الأعلى ضمن شهادات معهد LPI. يُشترط أن تكون لدى المترشح شهادة LPIC-2 صالحة إضافة إلى تجاوز اختبار تخصصي في أحد المجالات التالية: الأنظمة الهجينة Mixed Environment: يغطي Samba (إعداد النطاقات Domains، إدارة المستخدمين والمجموعات، وغيرها) إضافة إلى استخدام OpenLDAP والعمل على بيئة تتضمّن أجهزة لينكس ووندوز. الأمن والحماية Security: تشمل مواضيع الاختبار حماية الشبكات، العمليات والتطبيقات إلى جانب مبادئ التعمية والتحكم في الوصول Access controls. الأنظمة الافتراضيّة وعالية التوفر Virtualization & High Availability: يهتم بإدارة عناقيد Clusters للتوفر العالي إضافة إلى إشكاليات الأنظمة الوهمية. تتوفر اختبارات الشهادة بالإنكليزية واليابانية. معلومات إضافية تصل تكلفة إجراء شهادة Linux Essentials إلى 188 دولارا. بالنسبة لشهادات LPIC فالتسعير يكون حسب الاختبار، 110 دولارات لكل اختبار؛ أي 220 دولارا للشهادة. تُجرى الاختبارات على الحاسوب ويتضمن كل اختبار 60 سؤالا تنبغي الإجابة عنها في 90 دقيقة. الأسئلة هي من نوع الخيارات المتعددة وملْء الفراغات. تدوم صلاحية الشهادة خمس سنوات، ويمكن لصاحبها تجديد الشهادة بعد سنتين من حصوله عليها. كما أن الشهادات تُمدَّد تلقائيا لمن نال شهادة من المستوى الموالي، بحيث يُصبح تاريخ انتهاء صلاحية الشهادتين موافقا لتاريخ انتهاء صلاحية الشهادة الأخيرة. شهادات مؤسسة لينكس The Linux Foundation أنشئت مؤسسة لينكس سنة 2000 لدعم تطوير نظام التشغيل لينكس وتنسيق جهود المطورين. بدأت المؤسسة في 2014 برنامجا للشهادات المتخصّصة في لينكس إلى جانب برنامج للتكوين المفتوح على نظام تشغيل لينكس. تختلف شهادات منظمة لينكس عن الشهادات المذكورة أعلاه في كون الاختبارات تعتمد على أداء المترشح؛ فلا توجد أسئلة بخيارات متعدّدة أو لملء الفراغات مثل البقية بل يُطلب من المترشح تنفيذ إجراءات أو تُعرض عليه مشاكل ليحلها. كما أنها تشتهر بصعوبة الأسئلة وهو ما يجعلها من أكثر الشهادات تقديرا وتفضيلا لدى المشغِّلين. يختار المترشح إحدى التوزيعات التالية ليجري عليها الاختبار: CentOS 7، openSUSE 13.1 و Ubuntu 14.04. يتكون برنامج الشهادات المتخصّصة في لينكس الذي تقدمه الشركة من شهادتين: شهادة مدير أنظمة من مؤسسة لينكس Linux Foundation Certified System Administrator, LFCS وشهادة مهندس من منظمة لينكس Linux Foundation Certified Engineee, LFCE. 1. شهادة LFCS تركّز شهادة LFCS على قدرة الشخص على إجراء عمليات من المستوى المتوسط على سطر الأوامر، البحث عن المشاكل وتحليلها لإيجاد حلول فور حدوثها. تغطي الشهادة المجالات التالية: سطر الأوامر، نظام الملفات ووسائط التخزين، إدارة النظام المحلي، الأمن، برمجة سكربتات Shell وإدارة البرامج. تتوجه الشهادة إلى العاملين على بيئات عمل صغيرة ومتوسطة. يتطلب الحصول على شهادة LFCS تجاوز اختبار واحد يدوم ساعتين. ينبغي أن يحصُل المترشح على درجة 74% لتجاوز الاختبار. تبلغ تكلفة الاختبار 300 دولار؛ ويحق للمترشح الذي لم يحصُل على النسبة إعادة الاختبار مرة واحدة في ظرف 12 شهرا. 2. شهادة LFCE تمتحن شهادة LFCE قدرة المترشح على تصميم أنظمة معلومات تشتغل على لينكس وتنفيذ التصميم. تتضمن مجالات الشهادة: إدارة الشبكات، نظم الملفات الشبكية Network filesystems وخدمات الملفات، أمن الشبكات، الوصول عن بعد، خدمات HTTP وخدمات البريد. يُنتظَر من أصحاب هذه الشهادة أن يكونوا خبراء مرجعيين في مجال إدارة أنظمة لينكس. يدوم اختبار LFCE ساعتين ويجب على المترشح أن يتحصل على نسبة 72% لينال الشهادة. تبلغ تكلفة الاختبار 300 دولار؛ ويحق للمترشح الذي لم يحصُل على النسبة إعادة الاختبار مرة واحدة في ظرف 12 شهرا.
  12. صُمّمت شهادة Red Hat Certified System Administrator, RHCSA لاختبار المترشّح في المعارف والمهارات الضّروريّة المشتركة بين مختلف مجالات إدارة أنظمة لينكس. تعدّ شهادة RHCSA مدخل مسار الشهادات الخاصّ بـ Red Hat؛ وتليها شهادة Red Hat Certified Engineer التي تعدّ إحدى شهادات لينكس الأكثر قبولا. لماذا التقدم لشهادة RHCSA تتطلّب شهادة RHCSA الكثير من الاستعداد قبل التقدّم للامتحان؛ كما أنها مكلّفة. يجب أن تكون إجابة السّؤال “لماذا أريد هذه الشهادة؟” حاضرة في ذهنك قبل البدء في طريق الحصول عليها. في ما يلي أمور ينبغي الانتباه إليها قبل اتّخاذ القرار النهائي: شهادة RHCSA ضروريّة بالنسبة لبعض المؤسسات التي تعتمد بكثافة على حلول Red Hat التقنيّة. ستمثّل الشهادة إضافة محسوسة لسيرتك الذاتيّة مما قد يؤدّي إلى فرص وظيفية أكثر. ولكن يجب الانتباه أيضا إلى أن الحصول على الشهادة ليس ضمانا بالحصول على الوظيفة. يجب الاستمرار في العمل والتطوير المستمر لقدراتك. توفّر Red Hat موادّ دراسية جيدة للتحضير؛ ستحصُل على معرفة جيدة حول توزيعة Red Hat Enterprise Linux بمتابعتك لهذه الموارد الدراسية. إن كنت مدير نظم لينكس متمرّسا فسيحسّن التحضير للشهادة من مهاراتك ويزيد الحصول عليها من ثقتك بقدراتك. ينبغي الانتباه أيضا إلى أن الشهادة ليست بديلا عن الخبرة التي تكتسبها من العمل اليومي. قد لا تتجاوز الامتحان من أول محاولة وتضطّر بالتالي لدفع ثمن المحاولة مرة أخرى. يجب أن تكون على وعي بهذه المخاطرة؛ وأن تقبلها. تكلفة شهادة RHCSA وطريقة إجراء الامتحان تصلُح شهادة RHCSA لمدة ثلاث سنوات من تاريخ الحصول عليها. سير الامتحان يدوم امتحان الشهادة ساعتين ونصف، وهو امتحان تطبيقي لا مكان فيه للنظري؛ بمعنى أن لديك مهامّ ويجب تنفيذها. يبلغ عدد الأسئلة في العادة عشرين سؤالا مجموع درجاتها 300. الحد الأدنى للتجاوز هو 210 درجات. تُطرَح على كل مترشّح أسئلة فريدة (بمعنى أن الأسئلة تختلف من مترشّح لآخر) وتصله نتائج الامتحان بالبريد الإلكتروني في غضون سبعة أيام من إجرائه. تكلفة الشهادة يمكن تقسيم التكلفة الكليّة للشهادة إلى قسمين: تكلفة إجراء الاختبار وتكلفة التحضير له (اختياري). يكلّف التقدّم للاختبار حوالي 400$ حسب المنطقة الجغرافية. يمكن احتساب ما بين 200 إلى 300 دولار أمريكي في المواد الدراسية التحضيرية. نصائح قبل التقدم للشهادة الخبرة في إدارة الأنظمة مطلوبة لنيل الشهادة؛ إلا أنها ليست شرطًا لازما. يستطيع من ليست له خبرة كبيرة بإدارة أنظمة لينكس التقدّم للاختبار؛ إلا أن التحضير المكثّف جدا مطلوب في هذه الحالة. ستحتاج لمعرفة وحدات الاختبار والتركيز جيدا عليها لاستيعابها. “الممارسة ثم الممارسة” هي الوسيلة الوحيدة لفهم متطلبات الشهادة؛ طبّق كل خطوة من كل وحدة مرات ومرات. ربما تحتاج لثلاث أو أربع ساعات يوميا من التحضير لأسابيع متتالية وبوجود مواد تحضير جيدة حتى تنال الشهادة من أول محاولة. تفصّل صفحة الامتحان EX200 على موقع Red Hat الوحدات والمواضيع التي يُنتظَر من المترشح إتقانها. سلسلة دروس RHCSA تفترض هذه السلسة - على الأقل - معرفةً يسيرة بأوامر لينكس القاعديّة مثل: تبديل مجلّد العمل: أمر cd. سرد محتويات مجلّد: أمر ls. نسخ الملفات: أمر cp. نقل الملفات أو إعادة تسميتها: أمر mv. إنشاء ملفات فارغة أو تحديث الختم الزمني لملفات موجودة: أمر touch. حذف الملفات: أمر rm. إنشاء مجلّد: أمر mkdir. سنمرّ خلال دروس هذه السلسلة على بعض الأوامر أعلاه مع أمثلة مشروحة؛ كما يمكنك استخدام طرق مذكورة في السلسلة للحصول على معلومات أكثر عنها. يمكن الحصول على نسخة من توزيعة RHEL 7 من موقع مطوري Red Hat (هذه النسخة موجّهة للاستخدام الشّخصي فقط وينبغي ألا تُستَخدم في بيئة إنتاج). راجع سلسلة مقالات مدخل إلى لينكس إن كانت المواضيع أعلاه غريبة عليك. تتكوّن هذه السلسلة من 15 درسا تغطّي المواضيع التالية: مراجعة الأوامر الأساسيّة وكيفية الاستفادة من التوثيق Documentation. إدارة الملفات والمجلّدات. إدارة المستخدمين والمجموعات. التعامل مع الملفات النصّيّة: تحريرها بـ Nano و Vim؛ تحليلها بـ grep والتعابير النمطية. إدارة العمليات Process management. إعداد وسائط التخزين وتعميّتها. استخدام لوائح التحكم في الوصول Access control lists, ACL وتركيب المجلدات على الشبكة. تأمين SSH، ضبط اسم المضيِّف Hostname وتفعيل خدمات الشبكة. تثبيت خادوم ويب ونقل الملفات، إعداده وتأمينه. إدارة الحزم بـ Yum، جدولة المهام بـ Cron ومراقبة سجلات Logs النظام. أساسيات الجدار الناري Firewall ومراقبة الشّبكة. أتممة تثبيت RHEL 7 باستخدام Kickstart. أساسيات التحكّم في الوصول في SELinux. إعداد الاستيثاق Authentication بميثاق LDAP على RHEL 7. أساسيّات الحوسبة الافتراضيّة Virtualization وإدارة الضّيوف Guest بـKVM. تنبيه: اعتُمِد أثناء التخطيط للسلسلة على التفاصيل الواردة في صفحة الامتحان EX200 المذكورة أعلاه إذ أن Red Hat تشترط على المترشحين عدم نشر الأسئلة التي تُطرح عليهم في الامتحان. يجب التأكيد أن المصدر الرسمي الوحيد لأسئلة الامتحان هو Red Hat التي يمكن أن تغيّر مواضيعه إن رأت ذلك مناسبا.
  13. تستخدم المهام المجدولة باستخدام الأداة Cron لجدولة تنفيذ الأوامر في وقت محدد، حيث يمكن إعداد الأوامر أو السكربتات، التي يمكن أن يتم تنفيذها بشكل متكرر في وقت مجدد. يُعتبر Cron أحد أكثر الأدوات إفادة في أنظمة لينكس وشبيهات يونكس، حيث تعمل خدمة cron في الخلفية وتتحقق باستمرار من ملف etc/crontab/، ومجلّدات /.*etc/cron/، كما تتحقق من مجلد /var/spool/cron/. أمر crontab يستخدم أمر crontab لتثبيت، إلغاء تثبيت أو عرض الجداول (ملف إعدادات cron) المستخدم في قيادة خدمة cron في برمجية Vixie Cron. يمكن لكل مستخدم أن يكون لديه ملف crontab خاص به، وعلى الرغم من أنّها عبارة عن ملفّات في var/spool/cron/crontabs/ إلا أنها غير مخصصة ليتم التعديل عليها بشكل مباشر، حيث يجب استخدام الأمر crontab لتعديل أو إعداد أي مهام مجدولة في cron. أنواع ملفات إعدادات cron توجد أنواع مختلفة لملفات الإعدادات: Crontab الخاصة بأنظمة لينكس/يونكس عادةً ما تستخدم من قبل خدمات النظام والمهام المجدولة الحرجة التي تحتاج لصلاحيات مدير النظام root. ويستخدم الحقل السادس (انظر أدناه لمزيد من المعلومات عن الحقول) هو اسم المستخدم الذي سيتم تنفيذ الأمر وفق صلاحياته، وتعطي هذه المرونة إمكانية تنفيذ الأوامر وفق أي مستخدم. Crontab الخاصة بالمستخدم يمكن للمستخدم تثبيت مهامه المجدولة الخاصة باستخدام أمر crontab، ويستخدم الحقل السادس لتحديد الأمر المُراد تنفيذه، ويتم تنفيذ جميع الأوامر وفق المستخدم الذي قام بإنشاء المُهمّة. ملاحظة: يعرض المقال تطبيقات cron المكتوبة من قبل Paul Vixie والمستخدمة في معظم توزيعات لينكس وشبيهات يونكس كالإصدار الرابع الشهير لنظام BSD. إن الصيغة متوافقة مع العديد من تطبيقات خدمة crond. ولكن كيف أقوم بتثبيت وإنشاء مهامي المجدولة الخاصة؟ للقيام بذلك، نقوم بتنفيذ الأمر التالي في سطر الأوامر على أنظمة لينكس وشبيهات يونكس: $ crontab -e إن صيغة الملف الذي سيظهر على النحو التالي: 1 2 3 4 5 /path/to/command arg1 arg2 أو: 1 2 3 4 5 /root/ntp_sync.sh حيث أن: 1: الدقيقة (0-59) 2: الساعة (0-23) 3: اليوم في الشهر (0-31) 4: الشهر (0-12 حيث يمثل 12 شهر ديسمبر) 5: اليوم في الأسبوع (0-7 حيث يمثل الرقم 0 أو 7 يوم الأحد) path/to/command/: هو مسار السكربت أو اسم الأمر المراد جدولة تنفيذه. ويمكن تصوّر الصيغة على النحو الأسهل التالي: مثال على crontab بسيط: ## نفّذ سكربت backupscript كُل 5 دقائق ## */5 * * * * /root/backupscript.sh ## نفّذ سكربت backupscript يوميًا الساعة 1 صباحًا ## 0 1 * * * /root/backupscript.sh ## نفّذ سكربت backupscript شهريًا في اليوم الأول من الشهر في تمام الساعة 3:15 صباحًا ## 15 3 1 * * /root/backupscript.sh ملاحظة: يمكن إدراج تعليقات في ملف crontab بوضع إشارة # في بداية السطر. كيفية استخدام المعاملات operators لابد أنك لاحظت في الأمر الأول من الأوامر السابقة أننا كتبنا */5 بدلًا من 5 فقط. إنّ إشارة / هي إحدى المعاملات وسنرى الآن كيفية استخدام المعاملات في crontab. تسمح المعاملات بتحديد عدة قيم في الحقل الواحد، وهناك 4 معاملات: النجمة (*): يحدد هذا المعامل جميع القيم الممكنة في الحقل الذي استخدمت فيه. فعلى سبيل المثال، استخدام * في حقل الساعة يعني أنه سيتم تنفيذ الأمر في "كل" ساعة خلال اليوم، واستخدامها في حقل الأشهر يعني أنه سيتم تنفيذ الأمر في "كل" شهر من أشهر السنة. الفاصلة (,): يحدد هذا المعامل مجموعة من القيم، على سبيل المثال: "1,5,10,15,20,25"، فلو استخدمنا هذه السلسلة مثلًا في حقل الدقائق لعَنى ذلك أنه سيتم تنفيذ الأمر في الدقيقة الأولى، والخامسة، والعاشرة، والخامسة عشر، والعشرون، والخامسة والعشرون من الساعة. إشارة السالب (-): يحدد هذا المعامل مجالًا من القيم، على سبيل المثال: "5-15"، فلو استخدمنا هذه القيمة في حقل الأيام مثلًا لعَنى ذلك أنه سيتم تنفيذ الأمر في اليوم الخامس، السادس، السابع، .... الرابع عشر، الخامس عشر من كل شهر; وكما نلاحظ فهذا يشبه تمامًا كتابة "5,6,7,8,9,10,11,12,13,14,15" باستخدام معامل الفاصلة (,). الخط المائل الخلفي (/): يحدد هذا المعامل قيمة الخطوة، على سبيل المثال: "0-23/" يمكن استخدامها في حقل الساعة لتحديد أن الأمر سيتم تنفيذه في كُل ساعة، ويمكن استخدام هذا المعامل بعد معامل النجمة (*) فلو أردنا تنفيذ الأمر كل ساعتين فيمكن أن نكتب */2 في حقل الساعة. استخدام الكلمات الخاصة لتوفير الوقت عوضًا عن استخدام الحقول الخمسة الأولى من سطر crontab، يمكن استخدام إحدى الكلمات الخاصة الثمانية والتي لن توفّر الوقت فقط بل ستزيد من سهولة فهم المحتوى. reboot@: نفذ الأمر مرة واحدة عند كل إعادة تشغيل early@: نفذ الأمر مرة واحدة في بداية كل سنة، يماثل كتابة "0 0 1 1 *" annually@: مشابه لـ yearly@ تمامًا monthly@: نفذ الأمر مرة واحدة في بداية كل شهر، يماثل كتابة "0 0 1 * *" weekly@: نفذ الأمر مرة واحدة في بداية كل أسبوع، يماثل كتابة "0 0 * * 0" daily@: نفذ الأمر مرة واحدة في بداية كل يوم، يماثل كتابة "0 0 * * *" midnight@: مشابه لـ daily@ تمامًا hourly@: نفذ الأمر مرة واحدة في بداية كل ساعة، يماثل كتابة "0 * * * *" مثال: # نفذ أمر ntpdate كل ساعة @hourly /path/to/ntpdate المزيد من المعلومات عن ملف etc/crontab/ ومجلدات */etc/cron.d/ يُعدّ ملف etc/crontab/ خاصًا بالنظام، وعادة ما يستخدم من قبل مدير النظام root أو الخدمات لإعداد مهام مجدولة على مستوى النظام ككل، ويجب على المستخدمين استخدام أمر crontab لإعداد مهامهم المجدولة حسبما أوضحنا أعلاه. أمّا /var/spool/cron/ أو /var/cron/tabs/ فهي مجلّدات لملفّات crontab الخاصة بالمستخدم، ويجب إنشاء نسخة احتياطية عنها مع مجلد home الخاص بكل مستخدم. فهم ملف etc/crontab/ الافتراضي يحتوي الملف بشكل افتراضي على ما يلي: SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 01 * * * * root run-parts /etc/cron.hourly 02 4 * * * root run-parts /etc/cron.daily 22 4 * * 0 root run-parts /etc/cron.weekly 42 4 1 * * root run-parts /etc/cron.monthly يتم في البداية تحديد بيئة الصدفة SHELL، وفيما لو لم يتم تحديد البيئة سيقوم cron باستخدام الافتراضية sh. وفي حال لم يتم تحديد قيمة للمتغير PATH، فلن يكون هناك قيمة افتراضية ويتوجب حينها تحديد مسار الأمر أو السكربت المطلوب تنفيذه بشكل مباشر absolute. أما في حال لم يتم تحديد قيمة للمتغير HOME، فسيستخدم cron مسار مجلد home الخاص بالمستخدم الذي يقوم بالتنفيذ. بالإضافة إلى ما سبق، يقوم cron بقراءة الملفات في مجلد /etc/cron.d/، وعادة ما تقوم خدمات نظام مثل sa-update أو sysstat بوضع ملف مهامها المجدولة في هذا المجلّد. يمكن لمدير النظام root أو مستخدم بصلاحيات عالية superuser أن يستخدم هذه المجلّدات لإعداد المهام المجدولة، حيث بالإمكان إسقاط ملفات السكربتات في هذه المجلّدات مباشرة، ويقوم أمر run-parts بتنفيذ السكربتات أو البرامج الموجودة في مجلّد يتم تحديده في ملف etc/crontab/: ضع جميع السكربتات هنا واستدعيها في ملف etc/crontab/ /etc/cron.d/ نفذ جميع السكربتات مرة في اليوم /etc/cron.daily/ نفذ جميع السكربتات مرة في الساعة /etc/cron.hourly/ نفذ جميع السكربتات مرة في الشهر /etc/cron.monthly/ نفذ جميع السكربتات مرة في الأسبوع /etc/cron.weekly/ النسخ الاحتياطي للمهام المجدولة باستخدام cron يمكن استخدام الأمرين التاليين لأخذ نسخة عن المهام المجدولة للمستخدم الذي يقوم بتنفيذ الأمرين، حيث سيتم حفظ قائمة بالمهام المجدولة في الملف المحدد في المسار: # crontab -l > /path/to/file # crontab -u user -l /path/to/file يسمح الأمر الثاني بتحديد اسم المستخدم الذي سيتم عرض المهام المجدولة الخاصة به، ويتوجب أن يملك المستخدم الذي يقوم بتنفيذ الأمر صلاحية لاستعراض المهام المجدولة الخاصة بالمستخدم المذكور، فمثلًا يملك مدير النظام صلاحية تمكّنه من استعراض المهام المجدولة الخاصة بأي مستخدم، ولكن لا يمكن لأي مستخدم استعراض المهام المجدولة الخاصة بمدير النظام ما لم يكن يملك صلاحية بذلك. ترجمة -وبتصرّف- للمقال HOW TO ADD CRON JOBS IN LINUX AND UNIX لصاحبه Duy NguyenViet.
  14. سنلقي في هذا الدرس نظرةً إلى آلية التعامل مع الأخطاء و الإشارات أثناء تنفيذ السكربتات. يُقاس الفرق بين البرمجة الجيدة والتعيسة عادةً بمدة استقرار البرنامج ومرونته، أي قابلية تعامل البرنامج مع الحالات التي لا تسير فيها الأمور على ما يرام. حالة الخروج تتذكر من دروسنا السابقة أنَّ كل برنامج مكتوب بطريقة جيدة سيُعيد حالة خروج عندما ينتهي تنفيذه؛ فإذا انتهى تنفيذ البرنامج بنجاح، فستكون حالة الخروج مساويةً للصفر، وإن كانت حالة الخروج مساوية لقيمة مختلفة عن الصفر، فهذا يدلّ أنَّ البرنامج قد واجهة مشكلةً ما منعته من إتمام مهمته. من المهم جدًا التحقق من حالة خروج البرامج التي تستدعيها في سكربتاتك، ومن المهم أيضًا أن تُعيد سكربتاتك حالة خروج مفيدة عندما تنتهي. لقد مرّ عليّ مدير أنظمة يونكس قد كتب سكربتًا لنظام إنتاجي يحتوي على السطرين الآتيين: # 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.
  15. بعد أن تعلمنا التعامل مع المعاملات الموضعية (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.
  16. سنتعلم في هذا الدرس من سلسلة مدخل إلى كتابة سكربتات الصدفة كيفية إضافة "ذكاء" إلى سكربتاتنا، فإلى الآن كان يحتوي مشروعنا على سلسلة من الأوامر التي يبدأ تنفيذها من بداية الملف ويستمر سطرًا بسطر إلى أن يصل إلى نهاية الملف. لكن إمكانيات أغلبية البرامج أكبر من ما سبق، حيث تستطيع "اتخاذ القرارات" وإجراء عمليات مختلفة بناءً على مجموعة من الشروط. توفِّر الصَدَفة عدِّة أوامر يمكننا استخدامها للتحكم في جريان تنفيذ البرنامج، وسنتعلم في هذا الدرس: 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.
  17. بعد أن ازدادت السكربتات التي نكتبها تعقيدًا، فأحببت أن أشير إلى بعض الأخطاء الشائعة التي قد تصادفك أثناء مسيرتك. سنتعرض في هذا الدرس مثالًا ونعمل على تحليل الأخطاء التي قد نرتكبها، ولنسمِّ ذاك السكربت 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.
  18. عندما يزداد طول البرامج وتعقيدها، فستزداد صعوبة تصميمها وبرمجتها وصيانتها؛ لذا من المفيد عادةً تقسيم المهام الكبيرة إلى سلسلة من المهام الأصغر. سنُقسِّم في هذا الدرس السكربت الذي كنا نعمل عليه إلى عدد من الدوال (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.
  19. تتوفر آلاف الأوامر لمستخدمي سطر أوامر لينُكس، لكن كيف تستطيع تذكرها جميعًا؟ الجواب هو أنَّك لا تحتاج إلى ذلك؛ فالقوة الحقيقية للحاسوب تظهر عندما يقوم بالعمل عوضًا عنك، وذلك باستخدام سكربتات الصدفة (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.
  20. رأينا في الدرس السابق كيف كتبنا سكربتًا يولِّد صفحة 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.
  21. سنشرع في بناء تطبيق مفيد بدءًا من هذا الدرس، سيُنتِج هذا التطبيق مستند 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.
  22. قبل أن تبدأ في كتابة سكربتات جديدة، عليّ أن أشير إلى أنَّك تملك بعض السكربتات الموجودة مسبقًا، وضِعَت هذه السكربتات في مجلد المنزل الخاص بك عندما أُنشِئ حسابك، وتُستعمل لضبط سلوك جلسات سطر الأوامر في حاسوبك؛ تستطيع تعديل هذه السكربتات لتغيير بعض الأمور. سنلقِي نظرةً على سكربتَين من هذه السكربتات في هذا الدرس لكي نتعلم بعض المفاهيم الجديدة والمهمة عن الصَدَفة. يُبقي النظام على مجموعة من المعلومات حول جلستك تدعى "البيئة" (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.
  23. سنتحدثُ في هذا الدّرس عن الطرق التي يُوفّرها لك كلّ من Bash، نظام لينكس والطرفيّة Terminal للتّحكم بالوظائف والعمليّات. ذكرنا في درس إدارة العمليات في لينكس باستخدام الطرفية كيفية استعمال الأوامر ps ،kill و nice للتحكم بالمهام على نظامك. سنُركّز في هذا المقال على إدارة عمليّات المُقدّمة وعمليّات الخلفيّة وسنشرح كيف ترفع من مُستواك في التّحكم بالوظائف والمهام لتحصل على مُرونة أكثر عند تنفيذك للأوامر. إدارة عمليات المقدمة مُعظمُ العمليّات التي تُشغّلها على لينكس ستُنفّذ في المُقدّمة. سيبدأ الأمر بالتّنفيذ ما يمنعك من تنفيذ أي أمر آخر طوال مدة تنفيذ العمليّة. يُمكن أن تسمح العمليّة بتَفاعلِ المُستخدم، أو يُمكن أن تُنفّذ إجراءًا معيّنا ثم تنتهي. وسيُعرض أي مُستخرج على شاشة الطرفية افتراضيّا، سنتطرّق إلى الطريقة المُبسّطة لإدارة عمليّات المُقدّمة أسفله. تشغيل عملية تُشَغّلُ العمليّات في المُقدّمة افتراضيا إلى أن تنتهي أو عند تغيّر الحالة، وأثناء تشغيل العمليّات لن تتمكن من التفاعل مع الصّدفة Shell. بعض أوامر المُقدّمة تنتهي بسرعة مُرجعة المُستخدم إلى واجهة الصدفة آنيّاً، وهذا الأمر هو مثال على ذلك: echo "Hello World" هذا الأمر سيطبع "مرحبا بالعالم" على شاشة الطرفيّة ثم يرجعك إلى شاشة الأوامر. بعض أوامر المُقدمة الأخرى تأخذ وقتا أطول للتنفيذ، مانعة الولوج إلى الصّدفة أثناء التشغيل. يُمكن أن يعود السبب إلى أن الأمر يُشغل عمليّة أعقد أو أنّ العمليّة مُبرمجة للتنفيذ إلى أن تتوقف بشكل واضح أو إلى أن تتلقى مُدخلات من المُستخدم. تُعتبر أداة top من الأوامر التي تنفذ لوقت غير محدود، فبعد تشغيلها ستستمر في التنفيذ وتحديث عناصر الشاشة إلى أن يقوم المُستخدم بإنهاء العملية: top يُمكنك الخروج بالضّغط على "q". بعض العمليّات لا تملك طريقة للخروج ولتوقفها سيجب عليك استخدام طريقة أخرى. إنهاء عملية لنفترض أننا قمنا بتشغيل حلقة تكرار بسيطة في سطر الأوامر، يُمكننا تشغيل حلقة تكرار تقوم بطباعة "Hello World" كل عشر ثوان. هذه الحلقة ستستمر في الطّباعة إلى أن تُوقَف إجباريّاً: while true; do echo "Hello World"; sleep 10; done حلقات التكرار كهذه لا تملك أي زر للإلغاء، سيتوجّب علينا أن نوقف العمليّة بارسال ما يسمّى بـ الإشارة signal. تستطيع النواة في لينكس إرسال إشارات إلى العمليّات لطلب إيقاف نهائيّ للعملية أو تغيير الحالة فقط، طرفيّات لينكس عادة ما تكون مضبوطة لإرسال إشارة "SIGNT" (الإشارة رقم 2) لعمليّة المُقدّمة الحاليّة عند ضغط تركيبة المفتاحين CTRL+C. تُخبر إشارة "SIGNT" البرنامج بأن المستخدم قد طلب إنهاء العمليّة مُستخدما لوحة المفاتيح. لإيقاف حلقة التكرار التي بدأناها اضغط على مفتاحي CTRL و"c": CTRL+C سيتم إغلاق حلقة التكرار و ستتمكن من التحكم بالصّدفة Shell مجددا. إشارة "SIGNT" المُرسلة عن طريق تركيبة CTRL+C واحدة من الإشارات المتعدّدة التي يمكن إرسالها إلى البرامج، مُعظم الإشارات لا تملك تركيبة مفاتيح مُرتبطة بها، وعليك إرسال هذه الإشارات باستخدام الأمر kill عوضا عن ذلك (سوف نغطي ذلك لاحقاً). تعليق العمليات ذكرنا أعلاه أن عمليّات المُقدّمة تمنعك من تنفيذ أي أمر آخر طوال مدة تنفيذ العمليّة. ماذا لو أدركنا أنّنا نحتاج إلى شاشة الطرفية بعد أن نُشغّل عملية في المُقدمة؟ إشارة "SIGTSTP" (الإشارة رقم 20) هي إشارة من الإشارات التي يمكن إرسالها إلى عمليّات المُقدّمة. عندما نضغط تركيبة مفاتيح CTRL+Z، تُسجل الطرفيّة أمر "تعليق"، الذي يرسل إشارة "SIGTSTP" إلى عملية المُقدمة. هذا الأمر سيوقف مؤقّتا تنفيذ الأمر ويعيد التحكم بالطرفيّة. كمثال على ذلك، لنستخدم أمر ping للاتّصال ب google.com كلّ 5 ثوان. سوف نُسبق الأمر بكلمة command، ما يُخولُ لنا تجاوز أي كُنيات للصدفة (shell aliases) يُمكن لها وضع عدّ أقصى على الأمر : command ping -i 5 google.com عوضا عن إنهاء العملية باستعمال CTRL+C، أدخل CTRL+Z بدلا من ذلك. CTRL+Z سيكون المُخرج هكذا: [1]+ Stopped ping -i 5 google.com لقد تم إيقاف الأمر ping مؤقّتاً، وبذلك تستطيع الوصول إلى جلسة الصّدفة shell لكتابة الأوامر مُجدّداً. يُمكننا استعمال أداة إدارة العمليّات ps لعرضها: ps T PID TTY STAT TIME COMMAND 26904 pts/3 Ss 0:00 /bin/bash 29633 pts/3 T 0:00 ping -i 5 google.com 29643 pts/3 R+ 0:00 ps t يُمكننا ملاحظة أن عمليّة ping لا تزال ضمن القائمة، لكن العمود STAT (الخاص بحالة العمليّة) يحمل القيمة "T". صفحة الدليل الخاصة بـ ps تخبرنا أن هذا الحرف يعني أن العملية قد أوقفت عن طريق إشارة "التحكم بالعمليات". سوف نتحدّث بعمق أكثر عن كيفية تغيير حالة العمليّة،لكن في الوقت الحالي يُمكننا استئناف تنفيذ العمليّة في المُقدمة بكتابة: fg عند استكمال التنفيذ، أنهِ العمليّة باستعمال CTRL+C: CTRL+C إدارة عمليات الخلفية البديل الرئيسي لتنفيذ عمليّة في المُقدمة هو تشغيلها في الخلفيّة، عمليّة الخلفية مرتبطة بالطرفيّة التي شغّلتها منها، لكنّها لا تمنعك من الوصول إلى الصّدفة (سطر الأوامر)، عوضا عن ذلك، تُنفّذ العمليّة في الخلفيّة، تاركة لمُستخدم حريّة التفاعل مع النظام أثناء تشغيل العمليّة. بسبب الطريقة التي تتعامل بها عمليّات المقدمة مع الطرفيّة، يمكن أن تُشغّل عمليّة واحدة فقط لكل نافذة من نوافذ الطرفية. ولأن عمليّات الخلفية ترجع التحكم بالصّدفة Shell مباشرة بدون انتظار انتهاء العمليّة، يُمكن تشغيل العديد من العمليّات في الخلفيّة في الآن ذاته. تشغيل العمليات يُمكنك تشغيل عمليّة في المُقدّمة بإلحاق محرف"&" عند نهاية الأمر. يُخبر هذا الصّدفة shell بألّا تنتظر إلى حين انتهاء العملية بل تشغيلها وإرجاع التحكم بالطرفيّة للمُستخدم فوراً. ستبقى المُخرجات تُعرض على شاشة الطرفية (إلا إذا قمت بـإعادة توجيهها) لكنّك ستتمكن من كتابة أوامر إضافية أثناء استمرار تنفيذ عمليّة الخلفيّة. على سبيل المثال، يُمكن أن نبدأ أمر ping نفسه من القسم السّابق في الخلفيّة: command ping -i 5 google.com & سترى مخرجا يبدو هكذا من نظام bash للتحكم بالعمليّات : [1] 4287 وسترى أيضا المُخرج العادي من طرف الأمر ping: PING google.com (74.125.226.71) 56(84) bytes of data. 64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=1 ttl=55 time=12.3 ms 64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=2 ttl=55 time=11.1 ms 64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=3 ttl=55 time=9.98 ms رغم هذا ستتمكن من كتابة الأوامر في الوقت عينه. سوف يُمزج المُخرج من عمليّة الخلفيّة مع المدخلات والمخرجات الخاصة بعمليّة المُقدمة التي بدأتها، لكنّها لن تتداخل مع تنفيذ عمليّة المقدّمة. جدولة عمليات الخلفية لرؤية جميع العمليّات المُتوقفة أو عمليّات الخلفية، يمكنك استعمال الأمر jobs: jobs إذا كان الأمر ping مُشغّلا في الخلفية ستكون المخرجات على الشكل التالي: [1]+ Running command ping -i 5 google.com & يُبيّن هذا أنّنا نملك عمليّة واحدة في الخلفيّة. [1] تمثّل الـ "job spec" أو رقم الوظيفة. يُمكننا الإشارة إلى هذه العمليّة عند استعمال أوامر التحكم بالعمليّات مثل kill ،fg ،bg بإضافة سابقة "%" إلى رقم الوظيفة. في هذه الحالة سنشير إلى هذه الوظيفة بالإشارة 1%. إيقاف عمليات الخلفية يُمكننا إيقاف عمليّات الخلفيّة بعدّة طرق، أكثر طريقة نجاعة هي استخدام الأمر kill مع رقم الوظيفة. كمثال، يمكن أن نوقف أمرنا المُشغَّل في الخلفيّة بكتابة: kill %1 حسب طريقة ضبط الطرفيّة التي تستخدمها، إما مُباشرة أو بعض ضغط ENTER للمرة الثانية، ستشاهدُ حالة إيقاف الوظيفة على الطرفيّة: [1]+ Terminated command ping -i 5 google.com إذا تحققنا بالأمر jobs، سنلاحظ عدم وجود أي عمليّة. تغيير حالة العملية بعد أن تعرفنا على كيفية تشغيل عمليّة أو إيقافها في الخلفيّة، يُمكننا التحدث عن كيفية تغيير حالة العمليّة. شرحنا تغيير حالة واحدة قبل قليل عند التطرق لكيفيّة إيقاف مُهمّة أو تعليق عملها باستخدام CTRL+Z. يُمكننا نقل عمليّات المقدّمة إلى الخلفيّة أو العكس عندما تكون العمليّة في حالة توقّف. نقل عمليات المقدمة إلى الخلفية إذا نسيت أن تنهي الأمر بحرف العطف "&"، لا تزال قادرا على نقل هذه العمليّة إلى الخلفيّة. الخطوة الأولى هي إيقاف العمليّة باستخدام CTRL+Z: CTRL+Z عندما تتوقف العمليّة، يُمكننا استعمال الأمر bg لتشغيلها مجدّدا في الخلفيّة: bg ستشاهد حالة الوظيفة مع حرف العطف "&" ملحقا في الأخير: [1]+ ping -i 5 google.com & يعمل الأمر bg افتراضيّا مع آخر عمليّة تمت إيقافها، إذا أوقفت العديد من العمليّات بشكل متتالٍ بدون تشغيلها مجدّدا يُمكنك الإشارة إلى العمليّة برقم الوظيفة لإرسال العمليّة الصحيحة إلى الخلفيّة. لاحظ أنّه ليست كل العمليّات قابلة للإرسال إلى الخلفيّة. ستتوقف بعض العمليّات آليّاً إذا كشفت أنها نُفّذت مع إدخال ومخرج معياري متصلة مُباشرة مع طرفيّة نشطة. نقل عمليات الخلفية إلى المقدمة يُمكننا أيضاً نقل عمليّات الخلفيّة إلى المُقدّمة باستخدام الأمر fg: fg هذا الأمر يعمل مع آخر عمليّة منقولة إلى الخلفيّة، يُشار إليها بعلامة "+" في مخرجات jobs. الأمر يقوم فوراً بتعليق العمليّة ووضعها في المُقدّمة. لتحديد وظيفة أخرى استعمل رقم الوظيفة: fg %2 عندما تُنقل الوظيفة إلى المُقدّمة يُمكنك إمّا إنهاؤها مع CTRL+C، أو تركها لتكتمل أو تعليقها وإرسالها إلى الخلفيّة من جديد. التعامل مع إشارات SIGHUP سواء كانت العمليّة في المقدّمة أو في الخلفيّة، فستبقى مرتبطة بالطرفيّة التي بدأت العمليّة منها، عندما تغلق الطرفيّة فإنها ترسل إشارة SIGHUP لجميع العمليّات (في المُقدمة، في الخلفيّة، أو المتوقّفة) المرتبطة بها. ما يُشير إلى العمليّات بالإنهاء لأن الطرفيّة المُتحكِّمة ستصبح غير مُتوفرة قريباً، ماذا لو أردت إغلاق طرفيّة مع إبقاء تنفيذ عمليّات الخلفيّة؟ هناك العديد من الطرق للقيّام بذلك، أكثر الطرق مرونة هي باستعمال مُضاعف طرفيّة (terminal multiplexer) مثل tmux أو screen، أو استعمل أداة تمنح خاصية الفصل مثل dtach. على الرغم من هذا فهذه الطرق ليست دائما خيّارا ممكنا، ففي بعض الأوقات قد لا تكون هذه البرمجيات متوفرة أو أنّك قد سبق وبدأت العمليّة التي تريدها أن تستمر في التنفيذ بعد إغلاق الطرفيّة. استعمال nohup إذا كنت تعلم أنك عند تشغيل العمليّة سترغب في إغلاق الطرفيّة قبل انتهاء العمليّة، يُمكنك تنفيذها باستخدام أمر nohup، هذا الأمر يؤمّن العمليّة من التعرض إلى الإنهاء من طرف إشارة SIGHUP وستستمر في التنفيذ عندما تُغلق الطرفيّة. وستسجل كابن للنظام الأساسي: nohup ping -i 5 google.com & سترى سطرا يبدو كالتالي، مبيّنا أن مُخرجات الأمر ستُكتب في ملف يسمى nohup.out (في المجلّد الحالي إذا ما كان قابلا للكتابة عليه، في حالة لم يكن قابلا للكتابة عليه فسيُنشئه في مُجلّد المنزل): nohup: ignoring input and appending output to 'nohup.out' والغرض منه التأكد من أن المخرجات ليست مفقودة بعد إغلاق الطرفيّة. إذا أغلقت نافذة الطرفية وفتحت أخرى، ستبقى العمليّة في طور التنفيذ، ولن تتمكن من رؤيتها في مخرجات الأمر jobs لأن كل طرفيّة تحمل صفّ وظائف خاص بها، إغلاق الطرفيّة سبّب تدمير الوظيفة ping رغم أن العمليّة ping لا تزال تُنفّذ. لإيقاف عمليّة ping، يجب عليك البحث عن معرّف العمليّة (process ID) أو PID الخاص بها، يُمكنك القيّام بذلك بالاستعانة بالأمر pggrep (هناك أيضا الأمر pkill، لكنّنا بهذه الطريقة المقسّمة إلى خطوتين نكون متأكدين من أننّا سنوقف العمليّة التي نريدها فقط). استعمل pgrep مع a- للبحث عن العمليّة: pgrep -a ping المُخرجات: 7360 ping -i 5 google.com يُمكنك بعدها إيقاف العمليّة بإلحاق معرف العمليّة (الرقم في العمود الأول) بالأمر kill: kill 7360 قد ترغب في حذف ملف nohup.out إذا لم تكن تريده بعد الآن. استعمال disown يكون الأمر nohup مُفيدا فقط عندما تعلم أنّك ستحتاج إليه عند بدأ عمليّة ما. نظام إدارة الوظائف الخاص بـ bash يتيح لنا طرقا أخرى للحصول على نتائج مماثلة مع أمر diswon. عند الضبط الافتراضي للأمر disown، يقوم الأمر بحذف الوظيفة من طابور الوظائف الخاص بالطرفيّة. ما يعني أنك لن تستطيع إدارة العمليّة باستعمال التقنيّات التي تطرقنا إليها (مثل fg ،bg ،CTRL+Z ،CTRL+C). سيُحذف فوريّا من قائمة مخرجات الأمر jobs ولن يكون مرتبطا بالطرفيّة بعد ذلك. يُستعمل الأمر عن طريق تحديد العمليّة بالاستعانة برقم وظيفتها، على سبيل المثال، لتتبرر (disown) من الوظيفة رقم 2، يمكننا كتابة: disown %2 هذا الأمر سيترك الوظيفة في حالة مثل الأمر nohup، الاستثناء الوحيد هو أن جميع المُخرجات ستُفقد بعد إغلاق الطرفيّة في حالة لم يتم إعادة توجيهها إلى ملف ما. لن ترغب عادة في حذف العمليّة من قائمة التحكم بالوظائف إذا لم تكن تريد إغلاق نافذة الطرفيّة فورا.يمكنك إضافة h- للأمر لتقوم العمليّة بتجاهل إشارات SIGHUP، وتستمرَّ في العمل كوظيفة عاديّة: disown -h %1 في هذه الحالة، يُمكنك استعمال تقنيّات التحكم بالوظائف للاستمرار في التحكم بالوظيفة إلى حين إغلاق الطرفيّة، عند إغلاق الطرفيّة، ستكون عالقا -مرة أخرى- مع عمليّة دون أي مُخرجات إذا لم تعِد توجيهها إلى ملف عندما بدأتها. للعمل على ذلك، يمكنك محاولة إعادة توجيه مخرجات العمليّة بعد أن شغلتها. هذا الأمر خارج مجال هذا الدرس. يمكنك الإطلاع على الدرس مقدمة إلى إعادة توجيه الإدخال/الإخراج (I/O) في لينكس لمزيد من المعلومات. استعمال خيار الصدفة: huponexit هناك أيضا طريقة أخرى في Bash لتجنّب مشكلة إشارات SIGHUP للعمليّة الابن، يتحكم خيّار huponexit في ما إذا كان bash سيرسل إشارة SIGHUP للعمليّة الابن عند الخروج أو لا. ملاحظة: خيّار huponexit يؤثّر على طريقة تصرف إشارات SIGHUP فقط إذا كان إغلاق جلسة الصّدفة من داخل الصّدفة نفسه. يعتبر الأمر exit أو CTRL+D من الأمثلة على إغلاق الجلسة من داخل الصّدفة. عند إنهاء جلسة صدفة من برنامج الطرفيّة (بإغلاق النافذة، ...)، لن يكون للأمر huponexit أي تأثير، عوضا عن ترك اتخاذ قرار إرسال إشارة SIGHUP لـ bash سترسل الطرفيّة بنفسها الإشارة إلى bash، والتي ستبثّ (بشكل صحيح) الإشارة إلى العمليّة الابن. رغم المحاذير أعلاه، يعتبر خيار huponexit أسهل من الطرق. يُمكنك معرفة ما إذا كانت هذه الخاصية مُشغّلة أو لا بكتابة: shopt huponexit لتشغيل الخاصيّة: shopt -s huponexit الآن، إذا قمت بالخروج من الجلسة بالأمر exit، فإن العمليّات ستستمر في العمل: exit لدى هذا الأمر نفس المحاذير حول المُخرجات مع الخيّار السابق، لذلك تأكد أنّك قمت بتوجيه مُخرجات العمليّة قبل إغلاق الطرفيّة إذا كانت مُهمّة. خاتمة سيمنحك تعلّم التحكم بالوظائف وكيفيّة إدارة عمليّات المُقدمة وعمليّات الخلفيّة مرونة أكثر عند تشغيل البرامج من سطر الأوامر. عوضا عن فتح عدّة طرفيّات أو جلسات SSH، تستطيع أن تدبّر الأمر ببضع أوامر إيقاف وإرسال إلى الخلفيّة. ترجمة -وبتصرّف- للمقال How To Use Bash's Job Control to Manage Foreground and Background Processes لصاحبه Justin Ellingwood.
  24. نواصل معكم في هذا المقال استعراض أساسيات إدارة الحزم في أوبنتو ودبيان. إذا لم تقرأ الجزء الأول فأنصحك بقراءته أوّلا قبل مواصلة قراءة هذا المقال. إزالة الحزم وحذف الملفات العمليات المعاكسة لعملية التنصيب والتحميل الحِزم متاحة أيضًا من مدير الحِزم. هذا القسم سيناقش كيفية إزالة تنصيب الحِزم وتنظيف الملفات التي قد تبقى كنتيجة لعمل الحزمة. إزالة حزمة لإزالة حزمة منصبة، يجب إضافة الأمر الفرعي remove إلى الأمر apt-get. سيقوم هذا الأمر بإزالة الملفات التي قامت الحزمة بتنصيبها على نظامك مع استثناء جدير بالاهتمام. الأمر يُبقي ملفات الإعدادات محفوظة في مكانِ ما في حال تم إعادة تنصيب الحزمة مرة أخرى فيما بعد. تعتبر هذه الطريقة مفيدة في حالة الحذف المفاجئ للحزمة؛ حيث لا تضيع جهودك هدرًا في إعادة ضبط الإعدادات وتخصيصها. لإكمال العملية يلزمك تزويد الأمر باسم الحزمة المراد إزالتها أو إلغاء تصيبها: sudo apt-get remove package ستتم إزالة الحزمة، باستثناء ملف الإعدادات. إزالة حزمة وكل ملفات الإعدادات ذات العلاقة إذا كنت ترغب في إزالة حزمة وكل الملفات المتعلقة بها من نظامك، متضمنة ملفات الإعدادات، يمكنك استخدام الأمر الفرعي purge من الأمر apt-get. بخلاف الأمر remove -الذي تم ذكره بالأعلى- فإن الأمر purge يزيل كل شيء. تعتبر هذه الطريقة مفيدة في حال عدم رغبتك الاحتفاظ بملفات الإعدادات، أو في حال ما كانت لديك بعض المشاكل وترغب في البدء من الصفر. تجدر الإشارة هنا إلى أن ملفات الإعدادات لا يمكن استرجاعها في حال تم حذفها: sudo apt-get purge package في هذه الحالة، عندما تقوم بإعادة تنصيب الحزمة مرة أخرى فسيتم استخدام الإعدادات الافتراضية. إزالة الاعتماديات التلقائية التي لم تعد لها حاجة تتم إزالة الحِزم من النظام باستخدام الأوامر apt-get remove أو apt-get purge، لكن بعض هذه الحزم كان قد تطلّب وقت التنصيب بعض الاعتماديات لاستكمال التنصيب، وبعد إزالة الحزمة تبقى هذه الاعتماديات. لإزالة أي حِزم تم تنصيبها كاعتماديات ولم تعد مطلوبة لأي حزمة أخرى، يمكنك تنفيذ الأمر autoremove كما يلي: sudo apt-get autoremove إذا كنت ترغب في إزالة كل ملفات الإعدادات المتعلقة من الاعتماديات التي تمت إزالتها، يجب إضافة purge-- إلى الأمر autoremove. سيقوم هذا الأمر بإزالة ملفات الإعدادات مثل وظيفة الأمر purge: sudo apt-get --purge autoremove تنظيف ملفات الحزم المهجورة Obsolete بعض الحِزم تُصبح قديمة ومهجورة مع مرور الوقت. بإمكان الأداة apt-get إزالة أيٍ من ملفات هذه الحِزم عن النظام المحلي، تلك الملفات المرتبطة بالحِزم والتي لم تعد متاحة من قِبل المستودعات باستخدام الأمر autoclean. يقوم هذا الأمر بتحرير المزيد من المساحة على الخادوم، ويسمح بتحديث الذاكرة المؤقتة على النظام المحلي وتجنّب الاحتفاظ ببيانات غير مستخدمة. sudo apt-get autoclean الحصول على معلومات حول الحزم كل حزمة تحتوي على كمية كبيرة من البيانات التي يمكن الوصول إليها من خلال أدوات إدارة الحِزم. في هذا القسم سنقوم بتسليط الضوء على بعض الطرق الشائعة للحصول على المعلومات حول الحزم المتاحة والمنصبة. عرض المعلومات حول حزمة لعرض المعلومات التفصيلية حول حزمة في التوزيعة التي تستخدمها، يمكنك استخدام الأمر الفرعي show من الأمر apt-cache. هذا الأمر يعتمد على اسم الحزمة في المستودع: apt-cache show package سيقوم الأمر بعرض معلومات حول الحِزم التي تظهر في نتاج البحث عن تلك الحزمة التي يتم الاستفسار عنها. كل حزمة مرشحة تتضمن معلومات حول اعتمادياتها، الإصدار، التركيبة أو المعمارية، التعارضات، الاسم الفعلي للحزمة، حجم الحزمة وحجم تنصيبها، الوصف التفصيلي، بالإضافة إلى معلومات أخرى. لعرض المزيد من المعلومات حول كل حزمة مرشحة، شاملة لقائمة كاملة للاعتماديات العكسية ( قائمة الحِزم التي تعتمد على الحزمة التي نستفسر عنها) استخدم الأمر showpkg بدلا من الأمر المذكور أعلاه، والذي سيتضمن الكثير من المعلومات حول علاقة هذه الحزمة بالحِزم الأخرى: apt-cache showpkg package عرض المعلومات حول حزمة deb. لعرض تفاصيل حول ملف deb. يمكنك استخدام المؤشر info-- مع الأمر dpkg، الهدف لهذا الأمر يجب أن يكون مسار ملف deb.: dpkg --info debfile.deb سيعرض لك هذا الأمر بعض البيانات الوصفية حول الحزمة التي تستفسر عنها، المعلومات تتضمن اسم الحزمة وإصدارها، المعمارية التي بُنيت لها، الحجم والاعتماديات المطلوبة، الوصف والتعارضات. عرض الاعتماديات والاعتماديات العكسية لعرض الاعتماديات (اعتماد حزمة على أخرى) بشكل دقيق، وكذلك الاعتماديات العكسية (الحِزم التي تعتمد على هذه الحزمة) يمكنك استخدام الأداة apt-cache. لعرض معلومات الاعتماديات بشكل جيد، يمكنك استخدام الأمر الفرعي depends: apt-cache depends package سيقوم الأمر بعرض معلومات حول كل حِزمة تم التعرف عليها كاعتمادية، بالإضافة إلى الاقتراحات، التوصيات أو التعارضات. إذا كنت ترغب في معرفة أي حِزم تعتمد على حزمة معينة، يمكنك إضافة اسم الحزمة إلى الأمر الفرعي rdepends: apt-cache rdepends package عرض إصدارات الحزمة المنصبة والمتاحة في الكثير من الأحيان تتوفر عدّة إصدارات من حزمة ما في المستودع، مع حزمة واحدة افتراضية. لعرض الإصدارات المتاحة لحزمة ما، يمكنك استخدام الأمر الفرعي policy من الأمر apt-cache: apt-cache policy package سيقوم الأمر بعرض أي إصدار تم تنصيبه (إذا كان الحزمة منصبة)، الحزمة المرشحة والتي سيتم تنصيبها بشكل افتراضي إذا لم تقم بتحديد إصدار في أمر التنصيب، بالإضافة إلى جدول إصدارات الحزم، منتهيًا بمؤشر يشير إلى أولوية كل إصدار. يمكنك استخدام تلك الطريقة لتحديد أي إصدار سيتم تنصيبه والبدائل المتاحة. ولأن هذه الطريقة ترصد المستودعات التي يتواجد فيها كل إصدار، فإنه يمكن استخدامها لتحديد إذا ما توافرت مستودعات أخرى أو الأرشيف الشخصي للحِزم (PPAs) تقوم بنسخ الحِزم من المستودع الافتراضي. عرض الحزم المنصبة باستخدام الأمر dpkg -l لعرض الحِزم التي تم تنصيبها على نظامك، لديك القليل من الخيارات، اعتمادًا على هيئة المخرجات، وكذلك حجم المعلومات المطلوبة. الطريقة الأولى تتضمن استخدام dpkg أو dpkg-query مع l-. المخرجات من الأمرين كليهما ستكون متطابقة، بلا شك ستعطي قائمة لكل حزمة منصبة (جزئيا أو كليّا) على النظام، وشكلها كما يلي: dpkg -l Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) ||/ Name Version Architecture Description +++-===========================================-=======================================-============-===================================================================================================================== ii account-plugin-generic-oauth 0.10bzr13.03.26-0ubuntu1.1 amd64 GNOME Control Center account plugin for single signon - generic OAuth ii accountsservice 0.6.34-0ubuntu6 amd64 query and manipulate user account information ii acl 2.2.52-1 amd64 Access control list utilities ii acpi-support 0.142 amd64 scripts for handling many ACPI events ii acpid 1:2.0.18-1ubuntu2 amd64 Advanced Configuration and Power Interface event daemon . . . ستستمر المخرجات لكل حزمة في النظام على المخرجات يمكنك رؤية مدلولات الحروف الثلاثة الأولى في كل سطر. الحرف الأولى يشير إلى الحالة المرغوب فيها للحزمة، وتكون أحد ما يلي: u: غير معروف i: تم التنصيب r: تمت إزالتها. p: تمت إزالتها كليّا ( تنظيف بعد الإزالة) h: إصدار معلّق. الحرف الثاني يشير إلى الحالة الحقيقة للحزمة كما هو معروف لنظام التحزيم Packaging system، يمكن أن تكون إحدى الحالات التالية: n: لم يتم تنصيبها. i: تم تنصيبها. c: ملف الإعدادات موجود، لكن الحزمة تمت إزالتها. u: تم فك ضغط الحزمة لكن لم يُشرع في إعدادها بعد. f: الحزمة منصبة (جزئيًا) مما يعني حدوث فشل أثناء عملية التنصيب مما لم يسمح باكتمال عملية التنصيب. w: الحزمة تنتظر حدثًا من حزمة منفصلة. p: الحزمة تم تفعيلها من قِبل حزمة أخرى. الحرف الثالث، والذي يكون عبارة عن مسافة فارغة لأغلب الحِزم، له خيار واحد كما يلي: r: إشارة إلى ضرورة إعادة التنصيب، مما يفيد أن الحزمة غير مكتملة ولا يمكن الاستفادة من وظائفها. باقي الأعمدة تحتوي اسم الحزمة، الإصدار، المعمارية وكذلك الوصف. عرض حالة التنصيب للحِزم التي تم ترشيحها إذا قمت بإضافة معيار بحث بعد l- ، فإن dpkg سيعرض كل الحِزم التي تحوي معيار البحث، سواءً كانت منصّبة أم لا، على سبيل المثال، نستطيع البحث عن عمليات المكتبات YAML كما يلي: dpkg -l libyaml* Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend |/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad) ||/ Name Version Architecture Description +++-===============-============-============-=================================== ii libyaml-0-2:amd 0.1.4-2ubunt amd64 Fast YAML 1.1 parser and emitter li ii libyaml-dev:amd 0.1.4-2ubunt amd64 Fast YAML 1.1 parser and emitter li un libyaml-perl <none> (no description available) un libyaml-syck-pe <none> (no description available) ii libyaml-tiny-pe 1.51-2 all Perl module for reading and writing كما ترى في العمود الأول، النتيجة الثالثة والرابعة غير منصبة. هذا الأمر يعرض كل حزمة يتوفر فيها معيار البحث، بالإضافة إلى الحالة الحالية والمرغوب فيها. عرض الحِزم المنصبة بالأمر dpkg --get-selections يمكنك استعراض الحِزم المنصبة على نظامك بطريقة أخرى، باستخدام مؤشر get-selections-- مع الأداة dpkg، حيث يزودنا هذا الأمر بقائمة لكل الحِزم التي تم تنصيبها، والتي تمت إزالتها دون التنظيف بعد الإزالة: dpkg --get-selections للتفريق بين تلك الحالتين، يمكنك استخدام awk للتصفية حسب الحالة. لاستعراض الحِزم المنصّبة فقط، اطبع: dpkg --get-selections | awk '$2 ~ /^install/` لعرض قائمة الحِزم التي تمت إزالتها لكن لم يتم إزالة ملفات الإعدادات، يمكنك استخدام الأمر: dpkg --get-selections | awk '$2 !~ /^install/' البحث ضمن الحزم المنصبة للبحث في الحِزم المنصبة عن حزمة معينة، يمكنك إضافة نص التصفية/الترشيح بعد خيار get-selections--. هذا الأمر يستخدم البدائل لمحاولة العثور على تطابق ما. مرة أخرى، يقوم هذا الأمر بعرض أي حزمة منصبة، أو ملفات الإعدادات الخاصة بها ما زالت على النظام: dpkg --get-selections libz* مرة أخرى، يمكنك التصفية باستخدام تعبيرات awk من القسم أعلاه. استعراض الملفات المنصبة من خلال حزمة لاستعراض الملفات الخاصة بحزمة ما، يمكنك استخدام مؤشر L- مع الأمر dpkg: dpkg -L package سيقوم هذا الأمر بطباعة المسار الكامل لكل ملف خاص بتلك الحزمة. بالطبع لن تتضمن القائمة ملفات الإعدادات التي يتم إنشاؤها من خلال عمليات الحزمة البحث عن ما تنصبه الحزمة لموقع ما لاستكشاف أي حزمة مسؤولة عن ملف معين في نظام الملفات، يمكنك إضافة الملف الكامل إلى الأمر dpkg مع مؤشر S-. سيقوم الأمر بطباعة اسم الحزمة التي قامت بتنصيب الملف: dpkg -S /path/to/file تجدر الإشارة إلى أن أي ملفات تم نقلها إلى مكان ما من خلال عملية ما بعد التنصيب، لا يمكن ربطها بحزمتها من خلال هذا الأمر. معرفة أي حزمة تقوم بتوفير ملف ما دون تنصيبها قد تحتاج في بعض الأحيان لمعرفة أي حزمة تزودك بملف ما أو أمر ما، حتى بدون أن تقوم بتنصيب الحزمة على نظامك. من السهل معرفة إذا ما كانت حزمة معينة تحتوي ملفًا ما باستخدام dpkg بإضافة الخيار S-. لعمل ذلك يلزم تنصيب الأداة apt-file. تمتلك هذه الأداة قاعدة بيانات لمعلوماتٍ حول الحزم، من ضمن هذه المعلومات مسار التنصيب لكل ملف خاص بالحزمة من قاعدة البيانات تلك. قم بتنصيب الأداة بتنفيذ: sudo apt-get update sudo apt-get install apt-file الآن، قم بتحديث قاعدة البيانات الخاصة بالأداة وقم بالبحث عن ملف بتنفيذ: sudo apt-file update sudo apt-file search /path/to/file سيعمل هذا الأمر فقط للمواقع التي تم تنصيبها مباشرة بواسطة حزمة ما. لن يتم إيجاد الملفات التي تم إنشاؤها بواسطة برامج ما بعد التثبيت. تحويل قوائم الحزم بين الأنظمة في كثير من الأحيان قد تحتاج لعمل نسخة احتياطية لقائمة الحِزم التي تم تنصيبها على نظامك، واستخدامها لتنصيب نفس القائمة من الحِزم على نظام آخر. بالطبع تعتبر هذه الطريقة مفيدة لأغراض النسخ الاحتياطي. هذا القسم يوضح آلية تصدير واستيراد قوائم الحِزم. تصدير قائمة الحزم إذا كنت ترغب في تكرار مجموعة الحزم التي تم تنصيبها على نظامك إلى نظام آخر، يتوجب عليك في البداية تصدير قائمة الحزم. يمكنك تصدير قائمة الحزم المنصّبة إلى ملف بتلك الصيغة المطلوبة لاحقًا لعمية الاستيراد عن طريق مخرجات الأمر dpkg --get-selections : dpkg --get-selections > ~/packagelist.txt يمكنك نسخ هذه القائمة إلى نظام أو حاسوب آخر واستيرادها. قد تحتاج أيضًا لأخذ نسخة احتياطية لقوائم المصادر وقائمة المفاتيح الموثوقة. يمكنك أخذ نسخة احتياطية من المصادر بإنشاء مجلد بالملفات الضرورية ونسخها: mkdir ~/sources cp -R /etc/apt/sources.list* ~/sources المفاتيح الموثوقة يمكن نسخها احتياطيًا بتنفيذ: apt-key exportall > ~/trusted_keys.txt الآن يمكنك تحويل الملف packagelist.txt ومجلد sources والملف trusted_keys.txt إلى حاسوب آخر بغرض استيرادها. استيراد قائمة الحزم إذا قمت بإنشاء قائمة الحزم باستخدام dpkg --get-selections كما تم شرحه أعلاه، بإمكانك استيراد الحِزم على حاسوب آخر باستخدام الأمر dpkg . في البداية يجب أن تقوم بإضافة مفاتيح الثقة، وتحضير قوائم المصادر التي تم نسخها من الحاسوب الأول. على افتراض أنك قمت بنسخ جميع الملفات المنقولة إلى مجلد home في الحاسوب الثاني، يمكنك تنفيذ: sudo apt-key add ~/trusted_keys.txt sudo cp -R ~sources/* /etc/apt/ ثم قم بإزالة الحالة عن الحزِم غير الضرورية من الحاسوب الجديد. مما يعني أنك تقوم بتطبيق التغييرات من جديد. يجب تطبيق هذا من خلال حساب root أو صلاحيات sudo: sudo dpkg --clear-selections سيقوم الأمر باختيار كل الحِزم التي لا ترغب بتنصيبها. يجب أيضا تحديث قائمة الحِزم المحلية لضمان أن عمليات التنصيب سيكون لديها سجل أو معلومات لكل البرامج التي نحتاج تنصيبها. عملية التنصيب والتحدث الفعلية سيتم معالجتها من خلال أداة dselect. يجب التأكد أن الأداة dselect قد تم تنصيبها. تمتلك هذه الأداة قاعدة بيانات خاصة بها، لذا يجب تحديثها قبل الاستكمال: sudo apt-get update sudo apt-get install dselect sudo dselect update الآن نستطيع تطبيق قائمة الحزم فوق القائمة الحالية؛ لمعرفة أي حزم يجب الاحتفاظ بها أو تحميلها: sudo dpkg --set-selections < packagelist.txt يقوم هذا الأمر بضبط حالات الحزم التي نريدها. لتطبيق التغييرات يجب تطبيق الأمر الفرعي dselect-upgrade من الأمر apt-get: sudo apt-get dselect-upgrade سيقوم هذا الأمر بتحميل وتنصيب الحزم الضرورية. وسيقوم بإزالة الحزم التي لم يتم اختيارها. وفي النهاية فإن قائمة الحزم يجب أن تتطابق مع تلك التي تم استيرادها من الحاسوب الأول، بغض النظر عن أن ملفات الإعدادات ما زالت تحتاج لأن يتم نسخها أو تعديلها. إضافة المستودعات والأرشيف الشخصي للحزم PPA تحتوي المجموعة الافتراضية من المستودعات التي يتم توفيرها في أغلب التّوزيعات على حِزم كافية لأغلب المستخدمين. بالرغم من ذلك فإنك تحتاج في الكثير من الأحيان إلى مصادر إضافية. سنقوم في هذا القسم بمناقشة آلية أعداد أدوات الحزم لتتعامل مع مصادر إضافية. إضافة أرشيف شخصي للحزم يعتبر الأرشيف الشخصي للحزم (PPAs) بديلا عن المستودعات التقليدية. الأرشيف الشخصي للحزم متاح فقط لأنظمة أوبنتو، حتى كتابة هذا المقال. عادة ما يتميز الأرشيف الشخصي للحزم بمجال أصغر من المستودعات، ويحتوي مجموعة مركزة من التطبيقات التي يتم الاحتفاظ بها مِن خلال مَن يمتلك الأرشيف الشخصي للحِزم. إضافة أرشيف الشخصي للحزم لنظامك، يسمح لك بإدارة الحِزم التي يحتويها مع أدوات إدارة الحِزم التي اعتدت عليها. هذه الطريقة ستزودنا بحزمة أو مجموعة من الحِزم المحدّثة والتي لا يتضمنها مستودع الحِزم الخاص بالتوزيعة. يجب الانتباه إلى ضرورة إضافة الأرشيف الشخصي للحزم الذي تثق به، حيث أنك تسمح لحافظة غير رسمية ببناء الحِزم لنظامك. لإضافة أرشيف الشخصي للحزم، يمكنك استخدام الأمر add-apt-repository. يجب أن تضيف الاسم ppa:، متبوعًا باسم مالك الأرشيف الشخصي للحزم على Launchpad، شرطة مائلة ثم اسم الأرشيف الشخصي للحزم: sudo add-apt-repository ppa:owner_name/ppa_name قد يتطلب الأمر الموافقة على قبول مفتاح صاحب الحِزم. بعد ذلك سيتم إضافة الأرشيف الشخصي للحزم لنظامك، مما يسمح لك بتنصيب الحزم بأوامر apt الاعتيادية. قبل البحث عن الحزم أو تنصيبها، قمت بالتأكد من تحديث ذاكرة التخزين المؤقت المحلية بالمعلومات حول الأرشيف الشخصي الجديد للحِزم: sudo apt-get update إضافة مستودعات لإضافة المزيد من المستودعات لأنظمة أوبنتو أو دبيان، يمكنك اتباع أحدِ مسارين. المسار الأول يتم بتعديل قوائم المصادر لديك مباشرة. بإمكانك تعديل ملف etc/apt/sources.list/ أو استبدال ملف قائمة جديد في مجلد /etc/apt/sources.list.d/. إذا قمت باستخدام الطريقة الثانية فيجب الانتباه إلى أن اسم الملف الذي قمت بإنشائه يجب أن ينتهي بـ list.: sudo nano /etc/apt/sources.list.d/new_repo.list يمكنك إضافة موقع المستودع الجديد في الملف الجديد باستخدام الشكل التالي: deb_or_deb-src url_of_repo release_code_name_or_suite component_names الأجزاء المختلفة لمواصفات المستودع موضحة كما يلي: deb أو deb-src: لتحديد نوع المستودع. تستخدم deb لتحديد المستودع العادي، بينما مستودعات المصادر تبدأ بـ deb-src. url: العنوان الرئيسي للمستودع. يجب أن يكون الموقع الذي يتواجد فيه المستودع. release code name or suite: عادة ما يكون الاسم الرسمي لإصدار التوزيعة، لكن قد يكون أي اسم مستخدم لتعريف مجموعة محددة من الحِزم التي تم إنشاؤها للإصدار الذي تستخدمه من التوزيعة. component names: علامات لاختيار الحِزم التي ترغب بتوفرها. وتعتبر ميزة يتم توفيرها من القائمين على التوزيعة؛ لتقديم توضيح حول المصداقية أو قيود الترخيص للبرامج التي تحتويها. باستطاعتك إضافة هذه الأسطر بداخل الملف. معظم المستودعات تحتوي معلومات حول الهيئة التي يجب استخدامها. الطّريقة الأخرى لإضافة المزيد من المستودعات يتم باستخدام الأمر add-apt-repository. توزيعات أوبنتو تحتوي هذا الأمر بشكل افتراضي، بينما يمكن تنصيبها إلى توزيعات دبيان من خلال حزمة software-properties-common: sudo apt-get update sudo apt-get install software-properties-common بعد ذلك يمكن إضافة الأسطر التي تريد إضافتها إلى الأمر add-apt-repository. بالطبع يجب أن تكون الإضافات بنفس الهيئة أو الشكل الذي تستخدمه في حالة الإضافات اليدوية: sudo add-apt-repository 'deb url release component' يجب التأكد من تحديث الذاكرة المؤقتة المحلية للحِزم بعد تطبيق أي تحديث للمستودع؛ كي يكون النظام على وعي بالحِزم المتاحة حديثًا: sudo apt-get update خاتمة هناك العديد من عمليات إدارة الحِزم التي يمكنك إجراؤها، لكننا حاولنا تغطية أغلب الخطوات الشائعة هنا. إذا كان لديك أي تفضيلات أو اهتمامات أخرى، يرجى استخدام قسم التعليقات أدناه لنعرفها. ترجمة -وبتصرف- للمقال Ubuntu and Debian Package Management Essentials لصاحبه Justin Ellingwood.
  25. يعدّ أمر tar من بين الأدوات التي يشيع استخدامها في سطر أوامر لينكس، إلا أن جوانب مفيدة كثيرة في الأمر تبقى مجهولة. نعرض في هذا المقال بعض أشهر استخدامات الأمر tar إضافة إلى استخدامات رائعة أخرى يقل الانتباه إليها. أول ما تجب معرفته هو الغرض الأساسي من tar؛ إذ يعمل الأمر على جمع الكثير من الملفات في واحد. إذا نفذت أمر tar على مجلّد من 37 ملفّا فستحصُل على ملفّ واحد يضمّها جميعا وبالتي يسهُل مشاركتها مع الآخرين. كما أن الأمر يحافظ على بنية المجلّد ويمكن أن يحافظ على الأذونات ومعلومات الوقت والزمن كذلك. الخيارات في ما يلي قائمة بأهم الخيارات التي يمكن استخدامها مع tar. c: إنشاء ملف أرشيف. f: استخدام مُخرج الأمر لإنشاء ملف. تظهر مخرجات الأمر في الطرفية فقط إن لم يٍُستخدَم هذا الخيار. x: استخراج محتويات ملف أرشيف. j: استخدام خوارزمية bzip2 لضغط الملفات. z: استخدام خوارزمية gzip لضغط الملفات. p: الحفاظ على الأذونات عند استخراج الملفات. t: الحصول على قائمة بمحتويات ملف الأرشيف. v: عرض تقدّم عمل الأمر أثناء تنفيذه. d: عرض الفروق بين ملف الأرشيف ونظام الملفات. إنشاء ملف أرشيف إنشاء ملف أرشيف لمجلّد: tar cf directory.tar directory إنشاء ملفّ أرشيف انطلاقا من مجموعة ملفات: tar cf directory.tar file1 file2 file3 إنشاء ملف أرشيف مضغوط بخوارزمية bzip لملفات mp3 الموجودة في المجلّد الحالي: tar -cvf mp3collection.tar ./*.mp3 إنشاء ملف أرشيف من المجلد /home/academy/ مع الحفاظ على الأذونات: tar cvpf academy.tar /home/academy/ إنشاء أرشيف من المجلد etc/ مع استبعاد المجلد الفرعيّ apache2: tar cvf etc_without_apache.tar –exclude='/etc/apache2/' ضغط الملفات إنشاء ملف مضغوط بـbzip2 مع عرض تقدّم عمل الأمر في الطرفية: tar cjvf directory.tar.bz2 directory/ إنشاء ملف مضغوط بـgzip مع عرض تقدّم عمل الأمر في الطرفية: tar czvf directory.tar.gz directory/ عرض محتوى أرشيف عرض محتوى ملف الأرشيف directory: tar tvf directory.tar.bz2 ... bluewaters_1440x900.jpg cloudyday_1440x900.jpg fragile_1600x1200.jpg coolemoticon_1440x900.jpg cloudyday_1440x900.jpg ... الاستخراج من ملفات الأرشيف استخراج محتوى ملف أرشيف: tar xvf directory.tar.bz2 استخراج ملف passwd فقط من أرشيف etc: tar xvf etc.tar.bz2 passwd استخراج مجلد postfix فقط من أرشيف etc: tar xvf etc.tar.bz2 /etc/postfix/ استخراج ملفات php فقط من أرشيف htdocs: tar xvf htdocs.tar.bz2 –wildcards '*.php' الفروق الفرق بين ملف أرشيف ومجلّد (في حال عدم ذكر المجلد فالمقارنة تكون مع مجلد بنفس اسم الأرشيف في المجلد الحالي): tar df directory.tar.bz2 البحث عن ملف في الأرشيف: tar df directory.tar.bz2 directory/file1 ملحوظة: يجب في إصداراتٍ من tar تمرير خيار خوارزمية الضغط أثناء استخراج الملفات أو أثناء النظر في فروق ملفات أرشيف مضغوطة)؛ إلا أن الأمر اختياري في أغلب الإصدارات الأخيرة. مثلا: tar xjvf etc.tar.bz2 /etc/postfix/ بدلا من: tar xvf etc.tar.bz2 /etc/postfix/ ترجمة -وبتصرّف- لمقال A tar Primer لصاحبه Daniel Miessler.