أساسيات لينكس

أساسيات الطرفية والشل

18 دقيقة الدرس 2 من 26

أساسيات الطرفية والشل

كل خادم ستديره في الإنتاج يعمل بنظام Linux ويقبل الأوامر من خلال الطرفية. لا توجد واجهات رسومية، ولا قوائم نقر يمين، ولا سحب وإفلات. الطرفية هي الواجهة — وإتقانها هو المهارة الأعلى تأثيراً يمكن لمهندس DevOps تطويرها. قبل أن تتنقل في أنظمة الملفات أو تكتب pipelines، عليك أن تفهم ما الذي تتحدث إليه حقاً حين تفتح تلك النافذة السوداء.

الطرفية والشل والكونسول — ما الفرق؟

تُستخدم هذه الكلمات الثلاث بالتبادل في الحديث العام لكنها تعني أشياء مختلفة:

  • الطرفية (محاكي الطرفية): برنامج يرسم نافذة ويعالج إدخال لوحة المفاتيح ويعرض النص. أمثلة: gnome-terminal، iTerm2، Windows Terminal، alacritty. على خادم بعيد تتصل عبر ssh، وجلسة SSH نفسها تعمل كطرفية.
  • الشل: البرنامج الذي يعمل داخل الطرفية. يقرأ أوامرك ويفسّرها ويمررها إلى النواة. الشل هو المفسّر اللغوي — له متغيرات وحلقات ودوال وشروط. الشلات الشائعة: bash (الافتراضي في Linux)، zsh (الافتراضي في macOS منذ Catalina)، sh (شل POSIX متوافق وبسيط)، fish (الشل التفاعلي الودود)، dash (خفيف للغاية، كثيراً ما يكون /bin/sh في Ubuntu).
  • الكونسول: في الأصل كانت شاشة النص ولوحة المفاتيح المتصلة مباشرة بالخادم. في الاستخدام الحديث يعني عادةً الطرفية التي تحصل عليها عند تسجيل الدخول محلياً، أو الكونسول التسلسلي للمزود السحابي الذي تستخدمه حين يتعطل SSH.
الفكرة الأساسية: حين تكتب سكريبت شل بـ #!/bin/bash أو #!/bin/sh، تختار المفسّر — تماماً كاختيار Python 3 مقابل Python 2 بـ #!/usr/bin/env python3. سطر shebang مهم في الإنتاج لأن dash (في الغالب هو /bin/sh في Ubuntu) لا يدعم بنية Bash الخاصة مثل [[ أو local -n. استخدم دائماً #!/usr/bin/env bash في السكريبتات التي تحتاج ميزات Bash.

قراءة موجّه الشل (Prompt)

حين تفتح طرفية، يعرض الشل موجّهاً (prompt) — سلسلة قصيرة تخبرك أين أنت ومن أنت قبل انتظار الإدخال. فك شيفرته فوراً يوفّر الارتباك:

# صيغ الـ prompt الشائعة التي ستصادفها # الصيغة 1 — Bash الافتراضي في معظم خوادم Linux edrees@prod-web-01:~$ # الصيغة 2 — مستخدم root (لاحظ # بدلاً من $) root@prod-db-01:/etc/nginx# # الصيغة 3 — شائعة في حاويات Docker المصغّرة / CI bash-5.2$ # تشريح الصيغة 1: # edrees = اسم المستخدم الحالي # prod-web-01 = اسم المضيف (حرج — يخبرك أي خادم أنت عليه) # ~ = المجلد الحالي (~ اختصار لمجلد المنزل) # $ = محرف الموجّه ($=مستخدم عادي, #=root) # تحقق دائماً من اسم المضيف عند الاتصال بعدة خوادم. # حذف قاعدة بيانات خاطئة حدث بالفعل — وهو نهاية لمسيرة مهنية. hostname # طباعة اسم المضيف فقط whoami # طباعة المستخدم الحالي pwd # طباعة المجلد الحالي (مسار مطلق كامل)
مصيدة إنتاجية: دمّر مهندسون كبار بصلاحيات root على عشرات الخوادم بيانات الإنتاج بتنفيذ أوامر تدميرية على المضيف الخطأ. تحقق دائماً من hostname وwhoami قبل تنفيذ أي شيء لا يمكن التراجع عنه. بعض الفرق تلوّن موجّه الشل باللون الأحمر للخوادم الإنتاجية — إشارة بصرية تجبرك على التوقف والتفكير.

تشريح الأمر

كل أمر شل يتبع بنية متسقة. فهم هذه البنية يتيح لك قراءة أي أمر تصادفه، حتى لو لم تره من قبل:

Anatomy of a Shell Command ls -lh --sort=size /var/log 2>&1 | head -20 Command Short Flags Long Option + Value Argument (Path) Redirection Pipe to Next Cmd command [short-flags] [--long-option[=value]] [arguments] [redirections] [| pipe-chain] Items in [ ] are optional. Order matters: flags before arguments. Multiple short flags can combine: -lha = -l -h -a
التشريح الكامل لأمر الشل: اسم الأمر، الأعلام القصيرة، الخيارات الطويلة مع قيمها، وسيطات المسار، إعادة توجيه الإدخال/الإخراج، والأنبوب لأمر لاحق.

تحليل المثال: ls -lh --sort=size /var/log 2>&1 | head -20

  • ls — الأمر (سرد محتويات المجلد)
  • -lh — أعلام قصيرة مجمّعة: -l (تنسيق مفصّل) و-h (أحجام مقروءة للإنسان)
  • --sort=size — خيار طويل بقيمة: الترتيب حسب حجم الملف
  • /var/log — الوسيط: المجلد المراد سرده
  • 2>&1 — إعادة توجيه stderr (واصف الملف 2) إلى stdout (واصف الملف 1) حتى تظهر الأخطاء في الأنبوب
  • | head -20 — تمرير الإخراج إلى head، عرض أول 20 سطراً فقط

الحصول على المساعدة: man و --help وما هو أبعد

في شركات التقنية الكبرى، يعمل المهندسون بشكل اعتيادي مع أوامر لم يحفظوها. القدرة على إيجاد إجابات موثوقة بسرعة أكثر قيمة من حفظ الأعلام. يوفّر Linux عدة طبقات من التوثيق:

# الطبقة 1 — تذكير سريع بالأعلام (شبه عالمي) ls --help git commit --help # بعض الأدوات تفتح صفحة man الكاملة بدلاً من ذلك # الطبقة 2 — الدليل (صفحات man) man ls # الدليل الكامل لـ ls man 5 passwd # القسم 5 = تنسيقات الملفات (مقابل القسم 1 = أوامر المستخدم) man man # الدليل لنظام الدليل نفسه # داخل man: تنقل بمفاتيح الأسهم، ابحث بـ /، أنهِ بـ q # انتقل مباشرة لعنوان قسم: /^EXAMPLES # الطبقة 3 — apropos: بحث في صفحات man بالكلمة المفتاحية apropos "disk usage" # إيجاد أوامر تتعلق باستخدام القرص man -k crontab # نفس الشيء بعلم -k # الطبقة 4 — صفحات info (أدوات GNU لها توثيق أغنى هنا) info coreutils # توثيق GNU coreutils الكامل # الطبقة 5 — type / which / command: اكتشف ماهية الأمر فعلاً type ls # "ls is aliased to 'ls --color=auto'" أو "ls is /bin/ls" type cd # "cd is a shell builtin" — لا ملف ثنائي منفصل which python3 # المسار الكامل للملف الثنائي الذي سيُنفَّذ command -v git # النسخة المتوافقة مع POSIX من which (استخدمها في السكريبتات) # الطبقة 6 — tldr: أمثلة عملية من المجتمع (تثبيت منفصل) tldr curl # يعرض أكثر 5 أنماط استخدام شيوعاً لـ curl
ممارسة احترافية: في سكريبتات الشل، استخدم دائماً command -v بدلاً من which للتحقق من وجود برنامج. which ليس POSIX-standard ويتصرف بشكل متقلب عبر التوزيعات — في بعض الأنظمة يُرجع 0 حتى حين لا يوجد الأمر. الصيغة الصحيحة: if ! command -v docker >/dev/null 2>&1; then echo "docker not found"; exit 1; fi

أنواع الشل: التفاعلي مقابل غير التفاعلي، الدخول مقابل غيره

هذا الفرق يُوقع كل مهندس DevOps مرة على الأقل في الإنتاج. سلوك الشل — أي ملفات التهيئة يقرأها — يعتمد على طريقة تشغيله:

  • شل الدخول (Login shell): يبدأ عند تسجيل الدخول (SSH، su -، sudo -i). يقرأ /etc/profile، ثم ~/.bash_profile (أو ~/.profile). متغيرات PATH وJAVA_HOME وغيرها تُحمَّل هنا.
  • شل تفاعلي غير دخول: تبويب طرفية جديد، أو bash بدون -l. يقرأ ~/.bashrc. الأسماء المستعارة وتخصيص الـ prompt تعيش هنا.
  • شل غير تفاعلي: سكريبت شل يعمل في CI pipeline، أو مهمة cron، أو ssh host "command". يقرأ تقريباً لا شيء — لا .bashrc، لا أسماء مستعارة. هذا سبب فشل سكريبت يعمل محلياً في CI: /usr/local/bin في PATH تفاعلي لكن ليس في PATH السكريبت.
# تشخيص الملفات التي يقرأها الشل # طباعة كل ملف يُحمَّل أثناء الدخول (bash -x يتتبع التنفيذ) bash -xl 2>&1 | grep "^\+" | head -30 # التحقق من الشل الحالي وأعلامه echo $0 # "-bash" = شل دخول; "bash" = غير دخول echo $- # الأعلام: وجود "i" = تفاعلي # الحل القياسي لمشاكل PATH في CI: # في سكريبتك، حمّل ملف البيئة صراحةً، أو استخدم المسارات الكاملة source /etc/profile.d/myapp.sh # تحميل ملف بيئة محدد /usr/local/bin/node --version # استخدم المسار المطلق بدلاً من الاعتماد على PATH # في GitHub Actions / GitLab CI، ثبّت دائماً المسارات الكاملة أو # استخدم إجراءات setup-* التي تُصدّر صحيحاً إلى GITHUB_PATH / $PATH

سجل الشل واختصارات لوحة المفاتيح

السرعة الإنتاجية تأتي من عدم إعادة الكتابة. هذه الاختصارات ذاكرة عضلية للمهندسين ذوي الخبرة:

  • Ctrl+R — بحث عكسي في السجل؛ اكتب جزءاً من أمر لإيجاده
  • Ctrl+A / Ctrl+E — الانتقال إلى بداية / نهاية السطر
  • Ctrl+W — حذف كلمة واحدة إلى الخلف
  • Ctrl+L — مسح الشاشة (مثل clear)
  • !! — تكرار الأمر الأخير (الاستخدام الكلاسيكي: sudo !! بعد نسيان sudo)
  • !$ — آخر وسيط في الأمر السابق: mkdir /opt/myapp && cd !$
  • Alt+. — إدراج آخر وسيط من الأمر السابق (مثل !$ لكن تفاعلي)
  • Ctrl+C — إرسال SIGINT للعملية الأمامية (مقاطعة)
  • Ctrl+Z — إيقاف مؤقت للعملية الأمامية (ثم fg للاستئناف، bg للخلفية)
  • Ctrl+D — إرسال EOF؛ يغلق الشل الحالي إن كان الموجّه فارغاً
الفكرة الأساسية: يُحفظ سجل الشل في ~/.bash_history (افتراضياً 500-2000 سطر). في بيئات الإنتاج، كثيراً ما يُضبط HISTSIZE على رقم أكبر بكثير (50,000+) ويُهيَّأ HISTTIMEFORMAT ليُختم كل أمر بطابع زمني — أمر حرج في التحقيقات التي تسأل "ماذا نفّذ المهندس بالضبط ومتى؟"

ما يفعله الشل بمدخلاتك

فهم ترتيب توسيع الشل يمنع أخطاء خفية في السكريبتات ويمنع حقن الأوامر العرضي في CI pipelines:

  1. التقطيع إلى رموز: تقسيم الإدخال على المسافات البيضاء (ما لم تكن محاطة بعلامات اقتباس)
  2. توسيع الأقواس: {a,b,c}a b c
  3. توسيع التيلدة: ~/home/edrees
  4. توسيع المتغيرات: $VAR ← قيمتها
  5. استبدال الأوامر: $(command) ← إخراجها
  6. التوسيع الحسابي: $((1 + 2))3
  7. تقسيم الكلمات: تقسيم نتيجة التوسيع على IFS (افتراضياً: مسافة، تاب، سطر جديد)
  8. توسيع المسار (globbing): *.log ← أسماء الملفات المطابقة
  9. إزالة علامات الاقتباس: إزالة علامات الاقتباس التي جرى معالجتها
ممارسة احترافية: أحط توسيعات المتغيرات بعلامات اقتباس مزدوجة دائماً في السكريبتات: استخدم "$VAR" لا $VAR. بدون علامات الاقتباس، متغير يحتوي مسافات ينقسم إلى وسيطات متعددة كاسراً الأوامر بصمت. هذا مصدر فشل سكريبتات إنتاج لا تُحصى: rm -rf $DEPLOY_DIR مع DEPLOY_DIR="" يتوسع إلى rm -rf محذوفاً شجرة المجلد الحالي.