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



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

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

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

نوع المُحتوى


التصنيفات

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

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • ASP.NET
    • ASP.NET Core
  • سير العمل
    • 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

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

  1. Redis عبارة عن مخزن يعتمد على مفتاح وقيمته ويُعرف بمرونته، وأدائه، ودعمه العديد من اللغات. يوضح هذا المقال كيفية تثبيت وإعداد وتأمين Redis على خادم أوبونتو 18.04. المتطلبات ستحتاج إلى الدخول إلى خادم أوبونتو 18.04 والذي لا يملك صلاحيات مستخدم مسؤول ويملك صلاحيات sudo. بالإضافة إلى جدار حماية معد. يمكنك إعداد ذلك من خلال مقال التهيئة الأولية لِخادم أوبونتو. للبدء سجل دخولك إلى خادم أوبونتو 18.04 باستخدام مستخدم sudo وليس مستخدم مسؤول. خطوة 1 - تثبيت وإعداد Redis للحصول على أحدث إصدار من Redis، سنستخدم الأمر apt لتثبيته من متجر أوبونتو الرسمي. حدِّث ذاكرة التخزين المؤقتة لحزمة apt وثبت Redis باستخدام الأمرين التاليين: $ sudo apt update $ sudo apt install redis-server تنفيذ هذان الأمران سيؤدي إلى تنزيلRedis وتثبيته بالإضافة إلى تثبيت كل الأشياء المتعلقة به. بعد ذلك، يوجد إعداد مهم يجب تغييره في ملف إعداد Redis والذي وُلد تلقائيا أثناء التثبيت. افتح هذا الملف بأي محرر تفضله: $ sudo nano /etc/redis/redis.conf ابحث عن supervised في الملف. تتيح لك هذه التعليمة تعريف init في النظام لإضافة Redis كخدمة، مما يتيح لك تحكمًا أفضل بعملياته. تعليمة supervised تكون معطلة no بشكل افتراضي. غيِّر قيمة no إلى systemd؛ ذلك لأنك تستخدم أوبونتو المعتمد على نظام "systemd init". الملف ‎/etc/redis/redis.conf: . . . # If you run Redis from upstart or systemd, Redis can interact with your # supervision tree. Options: # supervised no - no supervision interaction # supervised upstart - signal upstart by putting Redis into SIGSTOP mode # supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET # supervised auto - detect upstart or systemd method based on # UPSTART_JOB or NOTIFY_SOCKET environment variables # Note: these supervision methods only signal "process is ready." # They do not enable continuous liveness pings back to your supervisor. supervised systemd . . . حتى الآن هذا هو التعديل الوحيد الذي نحتاج القيام به في ملف إعداد Redis. احفظ الملف واغلقه بعد تعديله. ثم أعد تشغيل خدمة Redis لتصبح التغييرات التي أجريتها على الملف سارية المفعول. $ sudo systemctl restart redis.service وبهذا تكون قد أعددت Redis، لكن قبل استخدامة يجب التأكد من أنه يعمل بالطريقة الصحيحة. خطوة 2 - اختبار Redis يفضل التأكد من صحة عمل أي برنامج جديد قبل تغيير أي من إعداداته. في هذه الخطوة سنتعرف على بعض الطرق للتأكد من ذلك. نبدأ بالتأكد من أن خدمة Redis تعمل: $ sudo systemctl status redis ستظهر مخرجات مشابهة لما يلي في حال كان Redis يعمل بدون أي أخطاء: المخرجات: ● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2018-06-27 18:48:52 UTC; 12s ago Docs: http://redis.io/documentation, man:redis-server(1) Process: 2421 ExecStop=/bin/kill -s TERM $MAINPID (code=exited, status=0/SUCCESS) Process: 2424 ExecStart=/usr/bin/redis-server /etc/redis/redis.conf (code=exited, status=0/SUCCESS) Main PID: 2445 (redis-server) Tasks: 4 (limit: 4704) CGroup: /system.slice/redis-server.service └─2445 /usr/bin/redis-server 127.0.0.1:6379 . . . يمكنك رؤية أن Redis مُفعَّل وقيد التشغيل، ما يعني أنه معد كي يبدأ التشغيل مع بدء تشغيل الخادم. ملاحظة: هذا الإعداد مستحسن في أغلب حالات استخدام Redis. إن كنت تفضل تشغيل Redis يدويا في كل مرة تحتاج إليه. يمكنك القيام بذلك باستخدام الأمر: $ sudo systemctl disable redis لاختبار صحة أداء Redis، اتصل بالخادم باستخدام سطر أوامر العميل: $ redis-cli في الشاشة التالية، اختبر الاتصال باستخدام أمر ping: 127.0.0.1:6379> ping المخرجات: PONG تأكد هذه المخرجات أن اتصال الخادم مفعل. بعد ذلك، تأكد من إمكانية إعداد المفاتيح باستخدام الأمر: 127.0.0.1:6379> set test "It's working!" المخرجات: OK استرجِع القيمة باستخدام الأمر: 127.0.0.1:6379> get test ستتمكن من استرجاع القيمة التي أدخلتها في حال كان كل شيء يعمل بشكل صحيح: المخرجات: "It's working!" بعد تأكدك من إمكانية استرجاع القيمة، أغلق شاشة تنفيذ أوامر Redis: 127.0.0.1:6379> exit كاختبار أخير لفحص ما إن كان Redis قادرا على الاستمرار حتى بعد إبقافة أو إعادة تشغيله. لتطبيق هذا الاختبار نبدأ بإعادة تشغيل Redis: $ sudo systemctl restart redis اتصل بشاشة أوامر عميل Redis مرة أخرى وتأكد من بقاء القيمة التي خزنتها: $ redis-cli 127.0.0.1:6379> get test يجب أن تظل القيمة المخزنة متاحة: المخرجات: "It's working!" أخرج مجددَا بعد انتهائك: 127.0.0.1:6379> exit وبذلك، يكون Redis مثبتَا ويعمل بشكل صحيح وجاهز للاستخدام. بالرغم من ذلك، ما تزال بعض إعداداته الافتراضية غير آمنة وتوفر بعض الفرص للأشخاص المخترقون للهجوم على الخادم وبياناته. تشرح باقي الخطوات في هذا المقال بعض الطرق لتقليل هذه الثغرات الأمنية كما ذكر في موقع Redis الرسمي. هذه الخطوات اختيارية وسيستمر Redis بالعمل حتى لو لم تنفذها، لكن يفضل أن تكمل هذه الخطوات لتقوية أمن نظامك. خطوة 3 - الربط مع المضيف المحلي (localhost) Redis متاح تلقائيا عبر المضيف المحلي، لكن إن كنت قد ثبتت Redis بطريقة أخرى فربما تكون قد حدَّثت ملف الإعداد الخاص ب Redis الأمر الذي يتيح اتصالات Redis من أي مكان. هذا الأمر غير آمن كالربط بالمضيف المحلي. لتصحيح الأمر، افتح ملف تكوين Redis لتعديله: sudo nano /etc/redis/redis.conf إذهب إلى السطر التالي وتأكد من إلغاء تعليقه (احذِف # إن وجدت): الملف /etc/redis/redis.conf: bind 127.0.0.1 ::1 احفظ الملف واغلقه عند الانتهاء (اضغط على CTRL + X, Y, ثم ENTER). أعد تشغيل الخدمة للتأكد من قراءة النظام للتغييرات: $ sudo systemctl restart redis للتأكد من تأثير هذه التغييرات، نفِّذ أمر netstat التالي: $ sudo netstat -lnp | grep redis المخرجات: tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 14222/redis-server tcp 0 0 ::1:6379 :::* LISTEN 14222/redis-server توضح هذه المخرجات أن برنامج خادم Redis مرتبط بالمضيف المحلي (127.0.0.1). مما يدل على انعكاس التغيير الذي أجريته على ملف التكوين. إن رأيت عنوان بروتوكول إنترنت آخر (مثل 0.0.0.0) فتأكد من إلغاء تعليق السطر المطلوب وأعد تشغيل خدمة Redis مجددَا. الآن وبعد أن أصبح Redis مربوطا بالمضيف المحلي فقط سيصبح من الصعب على جهات الاختراق تقديم الطلبات أو الوصول إلى الخادم. مع ذلك لا يزال Redis غير معد لِطلب المصادقة من المستخدمين قبل القيام بأي تغيير على إعداداته أو البيانات التي يحتفظ بها. لمعالجة هذا، يتيح لك Redis طلب تأكيد هوية من المستخدمين باستخدام كلمة مرور قبل إحداث ي تغيير وذلك باستخدام الأمر (redis-cli). خطوة 4 - إعداد كلمة مرور Redis يتيح لك إعداد كلمة مرور Redis تفعيل إحدى ميزات الحماية المدمجة فيه — الأمر auth يطلب من المستخدمين إثبات الهوية للوصول إلى قاعدة البيانات. يتم تكوين كلمة المرور مباشرة في ملف تكوين Redis "/etc/redis/redis.conf", لذلك؛ افتح الملف مجددا باستخدام محرِّرك المفضل: $ sudo nano /etc/redis/redis.conf انتقل إلى جزء "SECURITY" وابحث عن السطر التالي: الملف ‎/etc/redis/redis.conf: # requirepass foobared ألغِ تعليق هذا السطر بِإزالة "#" وغير "foobared" إلى كلمة مرور أكثر أمانًا. ملاحظة: يوجد تحذير معلق فوق الموجه "requirepass" في ملف "redis.conf": # Warning: since Redis is pretty fast an outside user can try up to # 150k passwords per second against a good box. This means that you should # use a very strong password otherwise it will be very easy to break. # لذلك، من المهم تحديد كلمة مرور طويلة. يمكنك استخدام الأمر "openssl" ِلتوليد كلمة مرور تلقائيا بدلا من القيام بذلك يدويا كما في المثال التالي. وذلك بتمرير مخرجات الأمر الأول إلى أمر "openssl" الثاني. سيزيل الأمر أي أسطر فارغة تم توليدها من الأمر الأول: $ openssl rand 60 | openssl base64 -A ستكون المخرجات مشابهة لما يلي: RBOJ9cCNoGCKhlEBwQLHri1g+atWgn4Xn4HwNUbtzoVxAYxkiYBi7aufl4MILv1nxBqR4L6NNzI0X6cE بعد نسخ ولصق المخرجات لتكون هي القيمة الجديدة ل "requirepass": /etc/redis/redis.conf requirepass RBOJ9cCNoGCKhlEBwQLHri1g+atWgn4Xn4HwNUbtzoVxAYxkiYBi7aufl4MILv1nxBqR4L6NNzI0X6cE بعد إضافة كلمة المرور، احفظ وأغلق الملف ثم أعد تشغيل Redis: $ sudo systemctl restart redis.service لِاختبار من عمل كلمة المرور، أدخل إلى سطر أوامر Redis: $ redis-cli الأوامر التالية تستخدم لاختبار ما إن كانت كلمة المرور تعمل أم لا. يحاول الأمر الأول إضافة مفتاح إلى قيمة قبل المصادقة: 127.0.0.1:6379> set key1 10 لن يتنفذ الأمر لعدم المصادقة وسيرجع Redis خطأ: المخرجات: (error) NOAUTH Authentication required. يقوم الأمر التالي بالمصادقة باستخدام كلمة المرور المحددة في ملف التكوين: 127.0.0.1:6379> auth your_redis_password يُأكد Redis المصادقة: المخرجات: ok بعد ذلك، سينجح الأمر السابق: 127.0.0.1:6379> set key1 10 المخرجات: ok الأمر "get key1" يطلب من Redis قيمة المفتاح الجديدة. 127.0.0.1:6379> get key1 المخرجات: ok يمكنك إغلاق "redis-cli" بعد تأكدك من أنه يمكنك تنفيذ أوامر عميل Redis: 127.0.0.1:6379> quit لاحقا، ستتعلم كيفية إعادة تسمية أوامر Redis والتي إن تم إدخالها بالخطأ أو من خلال جهة غير مُخَوًّلًة سيسبب الكثير من الأضرار لجهازك. خطوة 5 - إعادة تسمية الأوامر المهمة تتضمن ميزة الحماية الأخرى المدمجة في Redis إعادة تسمية بعض الأوامر التي تعتبر خطرة أو إلغاء تفعيلها. يمكن أن تستخدم بعض هذه الأوامر بواسطة مستخدمون غير مخولين بالدخول لإعادة إعداد، أو تدمير أو حذف بياناتك. سيتم إعادة تسمية الأوامر بنفس الجزء الذي تم تعديل كلمة المرور منه "SECURITY" من ملف "/etc/redis/redis.conf" بعض الأوامر المهمة والتي قد تكون ذات خطورة هي: FLUSHDB FLUSHALL KEYS PEXPIRE DEL CONFIG SHUTDOWN BGREWRITEAOF BGSAVE SAVE SPOP SREM RENAME DEBUG هذه القائمة ليست شاملة، لكن إعادة تسمية أو تعطيل هذه القائمة يعتبر بداية جيدة لتعزيز أمان خادم Redis. يعتمد إعادة تسمية أو تعطيل الأوامر على احتياجك لها لموقعك. إن كنت تعلم أنك لن تستخدم أمرًا ما؛ فيمكنك تعطيله. أو إعادة تسميته إن ان ذات أهمية لك. افتح ملف تكوين Redis لتفعيل أو تعطيل أي أمر: $ sudo nano /etc/redis/redis.conf تحذير: توضح الخطوات التالية كيفية تعطيل أو إعادة تسمية كأمثلة. يجب أن تختار تعطيل أو إعادة تسمية الأوامر التي تريدها فقط. يمكنك مراجعة قائمة الأوامر كاملة ومعرفة كيف يمكن أن تستخدم بطريقة ضارة على redis.io/commands. لِتعطيل أمر ما، أعد تسميته إلى نص فارغ (يشار إلى النص الفارغ بِعلامتي تنصيص "") كما في الأسفل: الملف ‎/etc/redis/redis.conf: . . . # It is also possible to completely kill a command by renaming it into # an empty string: # rename-command FLUSHDB "" rename-command FLUSHALL "" rename-command DEBUG "" . . . لإعادة تسمية أمر ما، اعطه اسما آخر كما في المثال بالأسفل. يجب أن تكون الأسماء صعبة التخمين للآخرين ولكن سهلة بالنسبة لك كي تتذكرها لاحقًا: الملف ‎/etc/redis/redis.conf: . . . # rename-command CONFIG "" rename-command SHUTDOWN SHUTDOWN_MENOT rename-command CONFIG ASC12_CONFIG . . . احفظ التغييرات وأغلق الملف. أعد تشغيل Redis بعد إعادة تسمية الأمر لتطبيق التغييرات: $ sudo systemctl restart redis.service أدخل إلى سطر أوامر Redis لاختبار الأمر الجديد: $ redis-cli قم بالمصادقة: 127.0.0.1:6379> auth your_redis_password المخرجات: OK لنفترض أنك أعدت تسمية الأمر "CONFIG" إلى "ASC12_CONFIG" كما في المثال السابق. أولا حاول استخدام الأمر الأصلي "CONFIG". يجب أن يفشل تنفيذ الأمر لأنك أعدت تسميته: 127.0.0.1:6379> config get requirepass المخرجات: (error) ERR unknown command 'config' سينجح الأمر عند استخدام الاسم الجديد. لا يهم حالة الأحرف. 127.0.0.1:6379> asc12_config get requirepass المخرجات: 1) "requirepass" 2) "your_redis_password" وأخيرا يمكنك الخروج من "redis-cli". 127.0.0.1:6379> exit ملاحظة: عندما تُعيد تشغيل سطر أوامر Redis، سيطلب منك إعادة المصادقة أو سيظهر لك الخطأ التالي عند محاولتك لتنفيذ أمر ما: المخرجات: NOAUTH Authentication required. ملاحظة: بالنسبة لإعادة تسمية الأوامر؛ يوجد جملة تحذيرية في نهاية جزء SECURITY في الملف "‎/etc/redis/redis.conf" والتي تنص على: Please note that changing the name of commands that are logged into the AOF file or transmitted to slaves may cause problems. يعني هذا التحذير أن إعادة تسمية الأوامر المحفوظة في ملف AOF أو المنقولة في ملف فرعي قد يتسبب ببعض المشاكل. ملاحظة: يستخدم Redis المصطلحات “master” و “slave” بينما يفضل DigitalOcean استخدام البدائل “primary” و “secondary”. ولتجنب الخلط بين المصطلحات فإننا نستخدم المصطلحات التي يستخدمها Redis في ملفات التوثيق الخاصة به. يعني ذلك أنه إن كانت الأوامر التي تمت إعادة تسميتها ليست في ملف AOF أو إن كانت فيه لكن لم يتم نقلها إلى مجلد فرعي فلن يكون هناك أية مشاكل. لذلك يجب أن تتذكر هذا عند قيامك بإعادة تسمية أمر ما. أفضل وقت لإعادة تسمية الأوامر هو عند عدم استخدامك ل AOF أو بعد التثبيت مباشرة قبل استخدام Redis. عند استخدامك ل AOF وتعاملك مع التثبيت بنوع master-slave، خذ بعين الاعتبار هذه الإجابة من صفحة المشروع على GitHub: الإجابة: تُسجَّل الأوامر في AOF ثم تُكرر إلى المجلدات الفرعية بنفس الطريقة التي تم إرسالها، لذلك إن شغَّلت AOF على نسخة لا تحتوي الأوامر التي تمت إعادة اسميتها ستواجه بعض التعارضات ولن تنفذ بعض الأوامر. لذلك فإن أفضل طريقة لإعادة تسمية لأوامر في مثل هذه الحالة هي عبر التأكد من أن الأوامر التي تمت إعادة تسميتها مطبقة على جميع النسخ في طريقة التثبيت باستخدام master-slave. الخلاصة ختاما، في هذا المقال، لقد ثبتته وإعداد Redis، وتأكدت من صحة عمل Redis، واستخدمت ميزات الحماية المدمجة فيه والتي تقلل عدد الثغرات الممكنة للهجوم من قبل المخترقين. تذكر أنه بمجرد تسجيل أحدهم الدخول إلى الخادم، فمن السهل عليه التحايل على إعدادت حماية Redis التي قمنا بها. لذلك فإن أهم ميزة أمان على الخادم هي جدار الحماية (الذي أعددته إن كنت تابعت المقال السابق حول التهيئة الأولية لخادم أوبونتو 18.04) الذي يجعل الاختراق صعبًا جدًا. ترجمة -وبتصرف- للمقال How To Install and Secure Redis on Ubuntu 18.04 لصاحبه الكاتب Mark Drake.
  2. عند إنشاءك خادم أوبونتو 18.04 للمرة الأولى، يجب عليك اتخاذ بعض الخطوات كجزء من الإعدادات الأولية. سيزيد ذلك من أمان وسهولة استخدام الخادم، ويمنحك أساسًا قويًا لإجراءات لاحقة. ملاحظة: يشرح المقال أدناه الخطوات التي نوصي بها لإكمال تهيئة خادم أوبنتو 18.04 يدويا. اتباع هذه الاعدادات اليدوية سيساعدك في تعلم بعض المهارات الأساسية لإدارة الخادم وكتمرين لفهم الإجراءات التي تحدث في الخادم بصورة عامة. إن كنت تريد تهيئة الخادم وبدء استخدامة بسرعة، يمكنك استخدام نصنا البرمجي لتهيئة الخادم الأولي والذي ينفذ خطوات التهيئة تلقائيا. خطوة 1 - تسجيل الدخول كمستخدم مسؤول (root) تحتاج لمعرفة عنوان بروتوكول الإنترنت العام (public IP) للخادم الخاص بك لتسجيل الدخول. تحتاج أيضا إلى كلمة المرور، أو المفتاح السري لمستخدم مسؤول (ما يسمى ب root users) إن كنت قد ثبتت مفتاح SSH للمصادقة. إن لم تكن قد سجلت الدخول إلى الخادم الخاص بك، فيمكنك اتباع المقال حول كيفية الاتصال ب Droplet باستخدام SSH. قم بتسجيل الدخول إلى الخادم كمستخدم مسؤول root إن كنت غير متصلا حتى الآن باستخدام الأمر التالي. استبدل النص المظلل بعنوان بروتوكول الإنترنت العام للخادم الخاص بك. $ ssh root@your_server_ip في حال ظهور تحذير عن موثوقية المضيف قم بقبوله. إن كنت تقوم بالدخول باستخدام إثبات الهوية؛ قم بتقديم كلمة المرور. أما إن كنت تستخدم مفتاح SSH المحمي بعبارة مرور (passphrase)، سيُطلب منك إدخال عبارة المرور في بداية كل جلسة. قد يُطلب منك أيضا تغيير كلمة المرور للمستخدم المسؤول root في أول مرة تقوم بالتسجيل بها. عن المستخدم root المستخدم المسؤول root في بيئة لينكس هو المتحكم والذي يمتلك صلاحيات عديدة. ونظرا لهذه الصلاحيات فلا ينصح باستخدامه دائمًا وذلك لتجنب القيام بتغييرات عن طريق الخطأ. الخطوة التالية هي إعداد مستخدم بديل بصلاحيات أقل للعمل اليومي. كما سنشرح كيفية إضافة صلاحيات في أي وقت تحتاج إليها. خطوة 2 - إنشاء مستخدم جديد بعد تسجيل دخولك كمستخدم مسؤول root، فأنت جاهز لإضافة حساب مستخدم جديد لاستخدامه من الآن فصاعدا. الأمر التالي يقوم بإنشاء مستخدم بالاسم sammy، يمكنك تسمية المستخدم بأي اسم تريده. # adduser sammy ستُعرض عليك بعض الاسئلة بدأَ بكلمة مرور للحساب الجديد. يجب أن تقوم بإدخال كلمة مرور قوية. ومن ثم تعبئة باقي المعلومات والتي تعتبر اختيارية ويمكنك تجاوزها بالضغط على زر ENTER. خطوة 3 - منح صلاحيات إدارية يمتلك الحساب الذي قمنا بإنشائه صلاحيات اعتيادية. لكن قد نحتاج في بعض الأحيان إلى صلاحيات إدارية. لتجنب الخروج من هذا المستخدم والدخول إلى المستخدم المسؤول root بكثرة؛ يمكننا إعداد ما يسمى بصلاحيات المستخدم الأعلى أو صلاحيات مسؤول root لحساب المستخدم العادي، مما يتيح للمستخدم العادي تنفيذ الأوامر التي تحتاج إلى صلاحيات إدارية عن طريق استخدام الكلمة "sudo" قبل كل أمر. لإضافة هذه الصلاحيات للمستخدم الجديد، نحتاج لإضافة هذا المستخدم إلى مجموعة sudo. يمكن للمستخدمين ضمن مجموعة sudo في اوبنتو 18.14 استخدام الأمر sudo. نفِّذ الأمر التالي لإضافة المستخدم الجديد إلى مجموعة sudo، يجب أن تكون متصلا بالخادم باستخدام حساب مسؤول root (استخدم اسم المستخدم الذي أنشأته مسبقا). # usermod -aG sudo sammy الآن يمكنك الدخول باستخدام الحساب الجديد وتنفيذ الأوامر ذات الصلاحيات العليا عن طريق كتابة "sudo" قبل هذه الأوامر. خطوة 4 - إعداد جدار حماية رئيسي يمكن لخادم أوبونتو 18.04 استخدام جدار الحماية Uncomplicated Firewall) UFW) -جدار الحماية في نظام لينكس- للتأكد من عدم الاتصال سوى بخدمات معينة. يمكن إعداد جدار حماية رئيسي بسهولة باستخدام تطبيق UFW. ملاحظة: إن كان الخادم الخاص بك يعمل على DigitalOcean؛ فيمكنك استخدام DigitalOcean Cloud Firewalls بدلا من تطبيق UFW وذلك يعد اختياريا. يستحسن استخدام جدار حماية واحد فقط لتجنب أي تعارضات والتي قد تكون صعبة التصحيح. يمكن لمختلف التطبيقات تسجيل ملفات التعريف الخاصة بها مع UFW أثناء تثبيتها. تسمح هذه الملفات لتطبيق UFW بإدارة هذه التطبيقات وفقا لاسم التطبيق. لدى خدمة OpenSSH (Open Secure Shell) -أداة الاتصال الأولى لتسجيل الدخول عن بُعد باستخدام بروتوكول SSH- التي تتيح لنا الاتصال بالخادم ملف تعريف مسجل لدى UFW. لرؤية ذلك نستخدم الأمر: # ufw app list المخرجات: Available applications: OpenSSH يجب التأكد من أن جدار الحماية يسمح لاتصالات SSH حتى نتمكن من تسجيل الدخول مرة أخرى. يمكن القيام بذلك باستخدام الأمر: # ufw allow OpenSSH ثم يمكننا تفعيل جدار الحماية: # ufw enable قم بإدخال الحرف "y" وقم بالضغط على "ENTER" للمتابعة، للتأكد من أن اتصالات SSH ما زالت تعمل نفذ الأمر: # ufw status المخرجات Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere OpenSSH (v6) ALLOW Anywhere (v6) في حال قمت بإعداد خدمات إضافية، قم بتعديل إعدادات جدار الحماية للسماح باتصالات هذه الخدمات؛ كون جدار الحماية يقوم بمنع الاتصالات عدا اتصالات SSH. يمكنك اتباع هذا المقال لتعلم بعض عمليات UFW الشهيرة. خطوة 5 - السماح بالوصول الخارجي للمستخدم الجديد بما أنه أصبح لدينا مستخدم جديد للاستخدام اليومي، سنحتاج للتأكد من أنه يمكننا الدخول إلى هذا المستخدم عبر SSH. ملاحظة: للتأكد من ذلك، يمكنك الدخول إلى المستخدم الجديد باستخدام كلمة المرور واستخدام sudo. يستحسن البقاء متصلا باسم المستخدم المسؤول root. بهذه الطريقة يمكنك تصحيح أي مشاكل وإضافة أي تعديلات تحتاجها. إن تستخدم واجهتك أي مشكلة في الاتصال بالمستخدم المسؤول root باستخدام SSH وكنت تستخدم DigitalOcean Droplet فيمكنك الدخول إلى Droplet باستخدام شاشة أوامر DigitalOcean. عملية إعداد وصول SSH لمستخدم الجديد تعتمد على ما إن كان حساب المستخدم المسؤول root يستخدم كلمة مرور أو مفتاح SSH للمصادقة. في حال كان المستخدم root يستخدم المصادقة بكلمة المرور إن كنت مسجلا دخولك إلى حساب المستخدم المسؤول root باستخدام كلمة مرور، فإن عملية المصادقة باستخدام كلمة المرور مفعلة ل SSH. مما يمكنك من إضافة SSH لحساب المستخدم الجديد عن طريق تنفيذ الأمر التالي مستخدما اسم المستخدم الذي انشأته سابقا: $ ssh sammy@your_server_ip بعد إدخال كلمة المرور الخاصة بالمستخدم الجديد؛ ستكون مسجلًا إلى النظام بالحساب الجديد ويمكنك تنفيذ الأوامر الإدارية من خلاله عن طريق إضافةsudoقبل الأمر: $ sudo command_to_run سيطلب منك النظام إدخال كلمة المرور الخاصة بالمستخدم الحالي لأول مرة من كل جلسة ومن ثم في بعض الأوقات فقط. لتعزيز أمان الخادم الخاص بك، يستحسن أن تقوم بإعداد مفاتيح SSH بدلا من استخدام كلمة المرور للمصادقة. يمكنك اتباع هذا المقال عن كيفية إعداد مفاتيح SSH على أوبنتو 18.04 لتتعرف على طريقة إعداد المصادقة المعتمده على المفاتيح السرية. في حال كان المستخدم المسؤول root يستخدم المصادقة بمفتاح SSH في حال كنت مسجلا الى حساب المسؤول root باستخدام مفاتيح SSH، فإن المصادقة باستخدام كلمة المرور ل SSH معطلة. للدخول إلى حساب المستخدم الجديد بنجاح، تحتاج لإضافة نسخة من المفتاح العام المحلي إلى الملف "‎~/.ssh/authorized_keys". يمكنك أيضا نسخ الملف "‎~/.ssh/authorized_keys" - والذي يحتوي على المفتاح العام الخاص بك- من حساب المسؤول root إلى الحساب الجديد باستخدام الجلسة الحالية. لنسخ الملف بطريقة سهلة وبالملكية والصلاحيات الصحيحة؛ نستخدم الأمر "rsync". سيقوم هذا الأمر بنسخ مجلد "‎.ssh" للمستخدم المسؤول root ،يحافظ على الصلاحيات ويقوم بتعديل ملكية الملفات في مرة واحدة. تأكد من وضع اسم المستخدم الجديد الذي أنشأته مسبقا. ملاحظة يتعامل الأمر "rsync" مع المجلدات التي تنتهي بشرطة مائلة "/" بطريقة مختلفة عن المجلدات التي لا تنتهي بشرطة مائلة. تأكد من أن أسماء المجلدات (‎~/.ssh) لا تنتهي بشرطة مائلة عند استخدام هذا الأمر"‎~/.ssh/‎". في حال أضفت شرطة مائلة في نهاية اسم المجلد عن طريق الخطأ في هذا الأمر، فسيقوم بنسخ محتويات المجلد من حساب المستخدم المسؤول root إلى المجلد الرئيسي لمستخدم "sudo" بدلا من نسخ الهيكل كاملا للمجلد "‎~/.ssh". وهكذا تكون الملفات في المكان الخاطئ ولن يتمكن SSH من العثور عليها واستخدامها. # rsync --archive --chown=sammy:sammy ~/.ssh /home/sammy الآن يمكنك استخدام SSH مع المستخدم الجديد عن طريق الأمر التالي في شاشة الأوامر: $ ssh sammy@your_server_ip يجب أن تقوم بالدخول إلى المستخدم الجديد بدون استخدام كلمة مرور. تذكر، لتنفيذ أمر باستخدام صلاحيات إدارية استخدم "sudo" قبل الأمر: $ sudo command_to_run ماذا بعد؟ الآن أصبح لديك إعدادات قوية للخادم الخاص بك. يمكنك تثبيت اي برنامج تحتاجه. اطلع على قسم لينكس في الأكاديمية لقراءة دليل آخر أو تعلم تثبيت برامج أخرى. ترجمة -وبتصرف- للمقال Initial Server Setup with Ubuntu 18.04 لصاحبه الكاتب Justin Ellingwood.
  3. نشرح في هذا الفيديو إدارة الملفات والمجلدات على نظام لينكس. الأوامر المشروحة في هذا الفيديو: pwd لطباعة المجلد الحالي cd للتنقل بين المجلدات ls لعرض الملفات والمجلدات touch لإنشاء ملفات جديدة mkdir لإنشاء مجلدات جديدة mv لنقل الملفات والمجلدات cp لنسخ الملفات والمجلدات rm لحذف الملفات والمجلدات ln لإنشاء وصلات رمزية وصلبة قسم لينكس في أكاديمية حسوب غني بالمقالات المفيدة التي تشرح مختلف جوانب استعمال هذا النظام.
  4. فلنفترض أنّ لديك مقطع فيديو طويلًا تريد قطع جزء من وسطه دون أن تكلّف نفسك عناء استيراد المقطع إلى محرّر فيديو، وقطع أجزاء منه، ثم تصديره من جديد. هذه الطريقة مملّة، وعلاوةص على ذلك تغيّر ترميز (Transcoding) الفيديو لغير حاجة. توجد طريقة سهلة لقصّ مقاطع الفيديو من سطر الأوامر باستخدام برنامج avconv عن طريق تنفيذ الأمر التالي في سطر الأوامر: avconv -i [input file] -ss [start time] -t [duration] -codec copy [output file] سنعطي مثالًا على كيفيّة تنفيذ الأمر أعلاه. فلنفترض أنّ لدينا مقطع فيديو يبدأ بـ 42 ثانية لا نرغب فيها. نحتاج لتعيين المعامل ‎-ss إلى القيمة 00:00:42. يقبل هذا المعطى رمزًا زمنيًّا بصيغة "ثوان:دقائق:ساعات". يخبر المعامل البرنامج أنّنا نريد الإبقاء على محتوى الفيديو الموجود بعد 42 ثانية. ماذا لو كانت لدينا 12 ثانيّة أخرى غير مرغوب بها في آخر الفيديو؟. في هذه الحالة يمكننا استخدام المعامل ‎-t لتحديد المدّة التي نريد الاحتفاظ بها من الفيديو. يوجد إشكال بسيط هنا، فقيمة المعامل ‎-t هي مدّة زمنيّة وليست نقطة زمنيّة محدّدة، وهذه المدّة هي الطول الإجمالي للمقطع الناتج. يعني هذا أنّ ما كان يوجد عند النقطة الزمنيّة 00:00:42 سيصبح عند 00:00:00 في الملفّ الناتج عن القصّ. وبالتالي إنْ أردنا قصّ 12 ثانيّة من آخر الفيديو فسنحتاج لعمليّة حسابيّة بسيطة. توجد طريقة سهلة تتمثّل في طرح قيمة المعامل ‎-ss من النقطة الزمنيّة التي تريد التوقّف عندها، واستخدام هذه القيمة في المعامل ‎-t. إذا كنّا نريد التوقّف عند النقطة 00:04:08 فإنّ قيمة ‎-t ستكون 00:03:26. نحصُل في النهاية على الأمر التالي: avconv -i input.mkv -ss 00:00:42 -t 00:03:26 -codec copy output.mkv لدينا الآن مقطع فيديو بطول 3 دقائق و26 ثانيّة. هذه هي طريقة قصّ الفيديو باستخدام avconv نظريّا. عمليًّا، قد تحتاج لتغيير بسيط. لسبب مّا لا يُنسَخ الصوت إلى الفيديو الناتج بطريقة جيّدة، لذا قد تحتاج لإعادة ترميز الصوت. إنْ واجهت هذه المشكلة فيمكنك التغلّب عليها بسهولة باستخدام الأمر التالي: avconv -i input.mkv -ss 00:00:42 -t 00:03:26 -c:v copy -c:a flac output.mkv يطلُب الأمرُ من البرنامج بنسخ ترميز الفيديو من المصدر، وفي نفس الأثناء إعادة ترميز الصوت إلى flac، الذي هو ترميز يضغط الصوت بدون فقد للمعلومات. ترجمة – بتصرّف – للمقال How to Trim Videos with the Command Line Using AVConv.
  5. نشرح طريقة تثبيت وإعداد خادم Apache أباتشي على توزيعة أوبنتو، وسنستعمله لتخديم صفحات HTML الخاصة بنا. لتثبيت خادم Nginx راجع فيديو تثبيت وضبط خادم Nginx في أكاديمية حسوب. قسم خوادم الويب في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها.
  6. نشرح طريقة تثبيت وإعداد خادم Nginx على توزيعة أوبنتو، وسنستعمله لتخديم صفحات HTML الخاصة بنا. لتثبيت خادم أباتشي راجع فيديو تثبيت وضبط خادم Apache في أكاديمية حسوب. قسم خوادم الويب في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها.
  7. نشرح طريقة تثبيت وإعداد خادم PostgreSQL على نظام أوبنتو 18.04. مع إعداد كلمة مرور للمستخدم root؛ وإنشاء قاعدة بيانات جديدة ومستخدم جديد لديه الصلاحيات الكاملة عليها. قسم PostgreSQL في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها: https://academy.hsoub.com/devops/servers/databases/postgresql/ نوفر توثيقًا كاملًا لجميع تعليمات SQL على موسوعة حسوب: https://wiki.hsoub.com/SQL
  8. نشرح طريقة تنصيب وإعداد خادم MySQL على نظام أوبنتو 18.04. مع إعداد كلمة مرور للمستخدم root؛ وإنشاء قاعدة بيانات جديدة ومستخدم جديد لديه الصلاحيات الكاملة عليها. نوفر توثيقًا كاملًا لجميع تعليمات SQL على موسوعة حسوب: https://wiki.hsoub.com/SQL
  9. بعد برمجتك لموقعك باستخدام روبي وإطار ريلز، حان الوقت الآن لنشر التطبيق على خادم (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
  10. نشرح طريقة الاتصال الآمنة عبر SSH بخوادم لينكس باستعمال برمجية PuTTY. وهذا يتضمن إعداد الوصول إلى الخادم عبر كلمة المرور، أو عبر مفتاح عام.
  11. لعلك تتساءل عن السبب الذي يجعلنا نستخدم 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
  12. تعرّفنا في الجزأين السابقيْن من هذا الدليل على كيفية عرض معلومات عن مساحات التخزين وإنشاء مساحات تخزين جديدة وتحجيمها. سنكمل في هذا الجزأ - الأخير من الدليل - ما تعلمناه سابقا ونتعرّف على المهمة الأخيرة من بين المهمّات الأساسية في إدارة التخزين بآلية 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.
  13. بعد أن تعرّفنا في الجزء السابق على كيفية عرض معلومات عن مختلف العناصر في 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.
  14. 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
  15. تتطلب الشهادات المتخصصة فهما عميقا ومعرفة جيّدة بمجال الشهادة والمهارات الضرورية لإنجاز الأعمال المرتبطة به. فهي تثبت امتلاك صاحبها للمعرفة والمهارات التي يبحث عنها المشغِّل من أجل اكتتاب موظّف قادر على البدء بالعمل في أقل وقت. إضافة إلى ذلك، تسوّق الشركات شهاداتِ موظفيها للزبناء لتتميّز عن المنافسين، وهو نفس السبب الذي يدفع المتخصّصين لنيل شهادات تميّزهم أثناء التقدم للعمل عن البقية؛ أو عن أقرانهم للحصول على فرص وظيفية أكبر. على مستوى شخصيّ، فإن التحضير والاستعداد لنيل الشهادة المتخصّصة - أو للمحافظة عليها - يجعل المتقدّم على اطّلاع مستمر بموضوع الشهادة ويساعده على اكتساب مهارات جديدة قد لا تكون متاحة له بطرق أخرى. لا يعدّ نظام تشغيل لينكس بدعا من المجالات التقنية الأخرى، بل إن الشعبية المتزايدة التي يحظى بها وسيطرته على غالبية الخواديم العاملة على الشبكة وفي النظم الداخلية للمؤسسات بمختلف أحجامها ومجالاتها؛ إضافة لرغبة الشركات في توظيف أشخاص قادرين على تولي مهمة إدارة الخواديم العاملة بلينكس افتراضيةً كانت أو حقيقة، بكفاءة وفعالية؛ يجعل نيل شهادة متخصصة أمرا مرغوبا إن لم يكن مشروطا في كثير من إعلانات الوظائف. يتوفّر سوق لينكس على الكثير من الشهادات المتخصّصة لتختار بينها سواء كان السبب الذي يدعوك للحصول على الشهادة فرصة وظيفية أفضل أو تأكيد معلوماتك وتحديثها. تختلف شهادات لينكس باختلاف الجهة التي تقف وراءها؛ فمنها الشهادة المتخصّصة في توزيعة واحدة ومنها الشهادات التي لا تعتمد على توزيعة معيّنة. هذه الأخيرة هي التي سنتحدث عنها في هذا المقال. شهادة 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 شهرا.
  16. صُمّمت شهادة 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 التي يمكن أن تغيّر مواضيعه إن رأت ذلك مناسبا.
  17. تستخدم المهام المجدولة باستخدام الأداة 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.
  18. سنلقي في هذا الدرس نظرةً إلى آلية التعامل مع الأخطاء و الإشارات أثناء تنفيذ السكربتات. يُقاس الفرق بين البرمجة الجيدة والتعيسة عادةً بمدة استقرار البرنامج ومرونته، أي قابلية تعامل البرنامج مع الحالات التي لا تسير فيها الأمور على ما يرام. حالة الخروج تتذكر من دروسنا السابقة أنَّ كل برنامج مكتوب بطريقة جيدة سيُعيد حالة خروج عندما ينتهي تنفيذه؛ فإذا انتهى تنفيذ البرنامج بنجاح، فستكون حالة الخروج مساويةً للصفر، وإن كانت حالة الخروج مساوية لقيمة مختلفة عن الصفر، فهذا يدلّ أنَّ البرنامج قد واجهة مشكلةً ما منعته من إتمام مهمته. من المهم جدًا التحقق من حالة خروج البرامج التي تستدعيها في سكربتاتك، ومن المهم أيضًا أن تُعيد سكربتاتك حالة خروج مفيدة عندما تنتهي. لقد مرّ عليّ مدير أنظمة يونكس قد كتب سكربتًا لنظام إنتاجي يحتوي على السطرين الآتيين: # 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.
  19. بعد أن تعلمنا التعامل مع المعاملات الموضعية (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.
  20. سنتعلم في هذا الدرس من سلسلة مدخل إلى كتابة سكربتات الصدفة كيفية إضافة "ذكاء" إلى سكربتاتنا، فإلى الآن كان يحتوي مشروعنا على سلسلة من الأوامر التي يبدأ تنفيذها من بداية الملف ويستمر سطرًا بسطر إلى أن يصل إلى نهاية الملف. لكن إمكانيات أغلبية البرامج أكبر من ما سبق، حيث تستطيع "اتخاذ القرارات" وإجراء عمليات مختلفة بناءً على مجموعة من الشروط. توفِّر الصَدَفة عدِّة أوامر يمكننا استخدامها للتحكم في جريان تنفيذ البرنامج، وسنتعلم في هذا الدرس: 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.
  21. بعد أن ازدادت السكربتات التي نكتبها تعقيدًا، فأحببت أن أشير إلى بعض الأخطاء الشائعة التي قد تصادفك أثناء مسيرتك. سنتعرض في هذا الدرس مثالًا ونعمل على تحليل الأخطاء التي قد نرتكبها، ولنسمِّ ذاك السكربت 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.
  22. عندما يزداد طول البرامج وتعقيدها، فستزداد صعوبة تصميمها وبرمجتها وصيانتها؛ لذا من المفيد عادةً تقسيم المهام الكبيرة إلى سلسلة من المهام الأصغر. سنُقسِّم في هذا الدرس السكربت الذي كنا نعمل عليه إلى عدد من الدوال (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.
  23. تتوفر آلاف الأوامر لمستخدمي سطر أوامر لينُكس، لكن كيف تستطيع تذكرها جميعًا؟ الجواب هو أنَّك لا تحتاج إلى ذلك؛ فالقوة الحقيقية للحاسوب تظهر عندما يقوم بالعمل عوضًا عنك، وذلك باستخدام سكربتات الصدفة (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.
  24. رأينا في الدرس السابق كيف كتبنا سكربتًا يولِّد صفحة 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.
  25. سنشرع في بناء تطبيق مفيد بدءًا من هذا الدرس، سيُنتِج هذا التطبيق مستند 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.