أوامر لينكس، الجزء 2: العمليات وأوامر DevOps
في الأسبوع الماضي تنقلت في نظام ملفات لينكس من الطرفية (terminal). وفي هذا الأسبوع نستخدم الطرفية للنظر في البرامج التي تعمل الآن. فكل أمر تكتبه يصبح عملية (process): نراقب العمليات بالأمرين ps وtop، وننهيها ونوقفها مؤقتا ونستأنفها بالأمر kill، ونغير أولويتها بالأمرين nice وrenice. ويجيب النصف الثاني عن سؤال ستسمعه في كل شركة برمجيات: ما معنى DevOps؟، ثم يتناول أوامر لينكس اليومية التي يستخدمها مهندس DevOps لقراءة السجلات (logs)، والمقارنة بين ملفات الإعدادات (configuration files)، وفحص الجهاز. أما نصف الساعة الأخير فلك: أسئلة على الورق، ثم مهام على جهاز أوبونتو الخاص بك.
أنتج كل خرج (output) في هذه الصفحة بتشغيل الأمر فعلا على نظام أوبونتو 24.04 بصفة مستخدم عادي اسمه student يسمح له باستخدام sudo. وكان ذلك النظام حاوية (container) صغيرة، ولذلك يشغل عمليات أقل كثيرا من آلتك الافتراضية، وتختلف فيه أسماء القرص والشبكة. وعندما تعيد تنفيذ الأوامر ستختلف عندك أرقام معرفات العمليات (process IDs) والأوقات وقيم الذاكرة؛ أما كل ما عدا ذلك فينبغي أن يطابق ما هنا.
الأهداف
بنهاية هذا الدرس ينبغي أن تكون قادرا على:
- شرح معنى العملية ومعرف العملية (PID)، والتمييز بين العملية التي تعمل في المقدمة (foreground) والعملية التي تعمل في الخلفية (background).
- تسمية حالات (states) العملية (قيد التشغيل، ونائمة، وموقوفة، وزومبي)، وقراءة حروفها
RوSوDوTوZ. - عرض العمليات بالأوامر
psوps -uوps -A، وقراءة الجدول الحي للأمرtop. - إنهاء عملية بالأمرين
killوkill -9، وإيقافها مؤقتا واستئنافها بالأمرينkill -STOPوkill -CONT، وشرح سبب تعذر قتل الزومبي (zombie). - بدء عملية بقيمة لطف (niceness) مختارة (
nice) وتغييرها لاحقا (renice)، وربطNIبـPRفيtop. - شرح معنى DevOps، وسبب حلوله محل فريقين منفصلين، وتسمية مراحل دورة حياته (lifecycle) مع أداة واحدة لكل مرحلة.
- استخدام مجموعة أوامر DevOps:
sudoوidوchownوgrepوsortوtailوcutوtrوsedوdiffوfindوddوtarوgzipوdfوduوfreeوhistoryوhostnameوifconfigوpingوtelnet.
قبل أن تبدأ: مجلد الدرس العملي
أنشئ مجلدا لهذا الدرس العملي واحفظ فيه الملفات التالية باستخدام محرر النصوص (Text Editor). وتستخدمها الأمثلة أدناه.
app.log، وهو سجل تطبيق صغير من عشرة أسطر:
2026-09-25 09:00:01 INFO web1 service started on port 8080
2026-09-25 09:00:05 INFO db1 connection pool ready
2026-09-25 09:01:12 WARN web1 slow response 1200 ms
2026-09-25 09:02:30 ERROR web2 cannot connect to db1
2026-09-25 09:02:31 INFO web2 retrying connection
2026-09-25 09:02:35 ERROR web2 cannot connect to db1
2026-09-25 09:03:00 info web2 connected to db1
2026-09-25 09:05:44 WARN db1 disk usage 85 percent
2026-09-25 09:06:10 INFO web1 deploy version 2.4 finished
2026-09-25 09:07:02 ERROR web1 out of memoryservers.txt (الاسم، والمدينة، والمنفذ (port)، وحجم الذاكرة RAM بوحدة GB، مفصولة بفواصل) وports.txt (رقم واحد في كل سطر):
web1,cairo,8080,4
db1,mansoura,5432,16
web2,alexandria,8080,4
cache1,cairo,6379,8
backup1,mansoura,22,328080
22
443
5432
80
3306config.old وconfig.new، وهما نسختان من ملف إعدادات واحد:
port=8080
workers=4
debug=true
log=/var/log/app.logport=9090
workers=4
debug=false
log=/var/log/app.log
timeout=30notes.txt (فيه أسطر فارغة عن قصد) وstubborn.sh، وهو سكربت (script) يرفض إشارة الإنهاء العادية:
deploy steps
build the code
test the code
ship it#!/bin/bash
# ignores the polite kill signal (15, SIGTERM)
trap '' TERM
while true; do
sleep 1
donehosts.txt، وفيه خمسة أسماء أجهزة (host names) بأحرف كبيرة وصغيرة مختلطة:
web1
DB2
cache1
Web3
db1اجعل السكربت قابلا للتشغيل بالأمر chmod +x stubborn.sh. والمجلد بعد اكتماله:
$ ls
app.log config.old db.old hosts.txt ports.txt sizes.txt
config.new db.new deploy.log notes.txt servers.txt stubborn.sh(تستخدم الملفات deploy.log وsizes.txt وdb.old وdb.new في قسم التمارين في النهاية.)
الجزء 1: العمليات
ما العملية؟
العملية هي برنامج قيد التنفيذ: نسخة عاملة من برنامج. وكل أمر تنفذه يبدأ عملية، ويعطي لينكس كل عملية رقما فريدا هو معرف العملية (process ID, PID).
العمليات نوعان:
| النوع | يسمى أيضا | السلوك |
|---|---|---|
| في المقدمة | تفاعلية (interactive) | تعتمد على المستخدم في الإدخال؛ وتنتظرها الطرفية |
| في الخلفية | غير تفاعلية، تلقائية | تعمل مستقلة عن المستخدم؛ وتبقى الطرفية متاحة |
إنهاء الأمر بالرمز & يبدؤه في الخلفية. فتطبع الصدفة (shell) رقم المهمة (job number) بين قوسين معقوفين ثم معرف العملية، وتعيد إليك المحث (prompt) فورا:
$ sleep 300 &
[1] 953لا يفعل sleep 300 شيئا لمدة 300 ثانية، وهذا يجعله عملية مناسبة وغير مؤذية للتجارب.
مثال محلول 1: من يعمل الآن؟
السؤال. بدأت طرفية جديدة للتو الأمر sleep 300 &. توقع خرج ps.
الإجابة.
$ ps
PID TTY TIME CMD
942 pts/0 00:00:00 bash
953 pts/0 00:00:00 sleep
954 pts/0 00:00:00 psثلاث عمليات: الصدفة bash التي تقرأ أوامرك، وsleep العاملة في الخلفية (معرفها 953، وهو الرقم نفسه الذي طبعته الصدفة)، وps نفسه. فتشغيل ps يبدأ عملية جديدة في كل مرة، ولذلك يظهر ps دائما في قائمته هو، بمعرف جديد في كل تشغيل.
حالات العملية
تمر العملية بحالات مختلفة بين إنشائها وانتهائها:
| الحالة | الحرف | المعنى |
|---|---|---|
| قيد التشغيل | R | تعمل، أو جاهزة للعمل |
| نوم قابل للمقاطعة | S | تنتظر توفر مورد؛ وتستيقظ لمعالجة الإشارات (signals) |
| نوم غير قابل للمقاطعة | D | تنتظر موردا؛ ولا تستيقظ للإشارات |
| موقوفة | T | استقبلت إشارة إيقاف |
| زومبي | Z | ميتة، لكن مدخلها ما زال موجودا في جدول العمليات (process table) |
الجزء 2: مراقبة العمليات بالأمرين ps وtop
الأمر ps: لقطة
يعرض الأمر ps (اختصار process status، أي حالة العملية) العمليات التي تعمل الآن. وبخلاف top، لا يتحدث خرجه في الوقت الحقيقي: إنه لقطة (snapshot). ويعرض ps وحده عمليات الطرفية الحالية:
| العمود | المعنى |
|---|---|
PID | معرف العملية |
TTY | الطرفية التي ترتبط بها العملية |
TIME | مجموع زمن المعالج (CPU) الذي استخدمته العملية |
CMD | الأمر الذي شغل العملية |
يعطي ps -u معلومات أكثر:
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 942 0.5 0.0 7608 4440 pts/0 Ss 08:03 0:00 bash
student 953 0.0 0.0 5688 2148 pts/0 S 08:03 0:00 sleep 300
student 955 0.0 0.0 10888 4352 pts/0 R+ 08:03 0:00 ps -u%CPU: مقدار قدرة المعالجة التي تأخذها العملية.%MEM: مقدار الذاكرة الذي تشغله العملية.STAT: حالة العملية. الحرف الأول هو الحالة من الجدول أعلاه؛ وتجاهل العلامات الإضافية بعده اليوم.
مثال محلول 2: اقرأ العمود STAT
السؤال. في خرج ps -u أعلاه، أي الأسطر نائمة، وأيها قيد التشغيل، ولماذا؟
الإجابة. bash (Ss) وsleep 300 (S) نائمتان: الصدفة تنتظر أن تكتب، وsleep تنتظر مؤقتها. أما ps -u (R+) فهي قيد التشغيل: ففي لحظة التقاط اللقطة تكون ps هي العملية التي تقوم بعمل قراءة الجدول.
الأمر ps -A: كل العمليات
لا يعرض ps وحده إلا عمليات هذه الطرفية. أما ps -A فيعرض كل العمليات، ومنها العمليات غير المرتبطة بأي طرفية (يكون TTY لها ?):
$ ps -A
PID TTY TIME CMD
1 ? 00:00:00 bash
7 ? 00:00:00 sleep
43 pts/0 00:00:00 bash
53 pts/0 00:00:00 sleep
54 pts/0 00:00:04 yes
56 pts/0 00:00:00 psالتقطت هذه القائمة في حاوية (container) صغيرة، والعملية 1 فيها هي الصدفة. أما على جهاز أوبونتو الخاص بك فالعملية 1 هي systemd، أول عملية يبدؤها النظام، والقائمة أطول كثيرا: فسطح المكتب وحده يشغل عمليات كثيرة. ولإيجاد برنامج واحد، مرر القائمة عبر أنبوب (pipe)، أي الرمز |، إلى grep، الذي لا يبقي إلا الأسطر التي تحتوي كلمة معينة:
$ ps -A | grep sleep
7 ? 00:00:00 sleep
53 pts/0 00:00:00 sleepالأمر top: العرض الحي
يعرض top العمليات العاملة في الوقت الحقيقي مع استهلاكها للذاكرة والمعالج، ويحدث العرض كل بضع ثوان. استخدم مفتاحي السهمين لأعلى ولأسفل للتنقل في القائمة، واضغط k لقتل العملية المظللة، و**q** للخروج.
التقطنا هنا خرج top مرة واحدة (top -b -n 1 يطبع شاشة واحدة ثم يخرج) بينما كانت العمليتان sleep 300 وyes > /dev/null تعملان في الخلفية. يطبع yes الحرف y إلى الأبد، ويتخلص > /dev/null من هذا الخرج، فلا يفعل yes شيئا سوى إبقاء المعالج مشغولا:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
54 student 20 0 5688 1976 1860 R 90.0 0.0 0:03.76 yes
1 root 20 0 4328 480 240 S 0.0 0.0 0:00.06 bash
7 root 20 0 2700 100 4 S 0.0 0.0 0:00.00 sleep
43 student 20 0 7608 4336 3728 S 0.0 0.0 0:00.07 bash
53 student 20 0 5688 2024 1916 S 0.0 0.0 0:00.01 sleep
55 student 20 0 11848 5420 3340 R 0.0 0.0 0:00.00 top| العمود | المعنى |
|---|---|
PID | معرف فريد يعطى لكل عملية |
USER | اسم المستخدم الذي يملك العملية |
PR | الأولوية (priority) التي تعطى للعملية في أثناء الجدولة |
NI | قيمة اللطف للعملية (العمود الرابع) |
VIRT | مقدار الذاكرة الافتراضية (virtual memory) التي تستخدمها العملية |
RES | مقدار الذاكرة الفعلية (physical memory) التي تستخدمها العملية |
SHR | مقدار الذاكرة المشتركة مع العمليات الأخرى |
S | الحالة: D نوم غير قابل للمقاطعة، وR قيد التشغيل، وS نائمة، وT متتبعة أو موقوفة، وZ زومبي |
%CPU | النسبة المئوية من المعالج التي تستخدمها العملية |
%MEM | النسبة المئوية من الذاكرة RAM التي تستخدمها العملية |
TIME+ | مجموع زمن المعالج الذي استهلكته العملية |
COMMAND | الأمر المستخدم لبدء العملية |
مثال محلول 3: من يستخدم المعالج؟
السؤال. قبل قراءة الجدول أعلاه، توقع العمودين S و%CPU للعملية sleep وللعملية yes.
الإجابة. لا ينتظر yes شيئا أبدا، ولذلك يكون دائما قيد التشغيل: R، ونحو 90% من معالج واحد (يتغير الرقم الدقيق مع كل تحديث). أما sleep فيقضي كل وقته في انتظار المؤقت: S و0.0. وسطر top نفسه حالته R لأنه كان العملية التي ترسم الشاشة.
الجزء 3: الإشارات بالأمر kill
الأمر kill يرسل إشارة
لإيقاف عملية، استخدم kill. ورغم اسمه (ومعناه القتل)، فإن kill يرسل إشارة إلى العملية، والإشارة هي التي تحدد ما يحدث. ويعرض kill -L كل الإشارات:
$ kill -L
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX| الأمر | الإشارة المرسلة | متى تستخدمه |
|---|---|---|
kill PID | 15، SIGTERM (الافتراضية) | لتطلب من العملية أن تنتهي |
kill -9 PID | 9، SIGKILL | عندما تتجاهل العملية طلب القتل العادي |
kill -STOP PID | 19، SIGSTOP | لإيقاف العملية مؤقتا |
kill -CONT PID | 18، SIGCONT | لتسمح لعملية موقوفة بأن تستأنف |
مثال محلول 4: القتل المهذب
السؤال. توقع خرج ps بعد هذين الأمرين.
$ sleep 300 &
[1] 84
$ kill 84الإجابة.
$ ps
PID TTY TIME CMD
72 pts/0 00:00:00 bash
91 pts/0 00:00:00 ps
[1]+ Terminated sleep 300بلا رقم، يرسل kill الإشارة 15، أي SIGTERM. فتنتهي sleep وتختفي من الجدول، وتبلغ الصدفة عن المهمة بأنها Terminated.
مثال محلول 5: عملية تتجاهل kill
السؤال. يطلب stubborn.sh (انظر مجلد الدرس العملي) من الصدفة أن تتجاهل SIGTERM، ثم ينام في حلقة. توقع ما يعرضه ps بعد kill 92، وبعد kill -9 92.
الإجابة.
$ ./stubborn.sh &
[1] 92
$ kill 92
$ ps
PID TTY TIME CMD
72 pts/0 00:00:00 bash
92 pts/0 00:00:00 stubborn.sh
104 pts/0 00:00:00 sleep
105 pts/0 00:00:00 ps
$ kill -9 92
$ ps
PID TTY TIME CMD
72 pts/0 00:00:00 bash
113 pts/0 00:00:00 ps
[1]+ Killed ./stubborn.shبعد kill 92 يبقى السكربت موجودا (وsleep التي تحته هي نومة الثانية الواحدة في حلقته): فقد تجاهل السكربت الإشارة SIGTERM. أما SIGKILL، أي الإشارة 9، فلا يمكن تجاهلها، ولذلك ينهيه kill -9 وتبلغ الصدفة بالرسالة Killed. لا تستخدم kill -9 إلا عندما لا ينجح القتل العادي: فالعملية لا تحصل على فرصة لإنهاء عملها بطريقة نظيفة.
الإيقاف والاستئناف
تدخل العملية الحالة موقوفة عندما تستقبل إشارة إيقاف:
$ sleep 300 &
[1] 130
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 120 2.7 0.0 7608 4280 pts/0 Ss 08:06 0:00 bash
student 130 0.0 0.0 5688 2024 pts/0 S 08:06 0:00 sleep 300
student 131 0.0 0.0 10888 4344 pts/0 R+ 08:06 0:00 ps -u
$ kill -STOP 130
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 120 1.7 0.0 7608 4340 pts/0 Ss 08:06 0:00 bash
student 130 0.0 0.0 5688 2024 pts/0 T 08:06 0:00 sleep 300
student 138 0.0 0.0 10888 4432 pts/0 R+ 08:06 0:00 ps -u
[1]+ Stopped sleep 300
$ kill -CONT 130
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 120 1.2 0.0 7608 4348 pts/0 Ss 08:06 0:00 bash
student 130 0.0 0.0 5688 2024 pts/0 S 08:06 0:00 sleep 300
student 145 0.0 0.0 10888 4300 pts/0 R+ 08:06 0:00 ps -uغير -STOP حالة sleep من S إلى T، وأبلغت الصدفة عن المهمة بأنها Stopped. وأعادها -CONT إلى S.
مثال محلول 6: قتل عملية موقوفة
السؤال. العملية sleep 300 موقوفة. نرسل إليها kill الافتراضي. هل اختفت؟ وماذا يحدث عندما نرسل بعد ذلك -CONT؟
الإجابة.
$ sleep 300 &
[1] 366
$ kill -STOP 366
$ kill 366
[1]+ Stopped sleep 300
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 358 0.2 0.0 7612 1968 pts/0 Ss 08:39 0:00 bash
student 366 0.0 0.0 5688 112 pts/0 T 08:39 0:00 sleep 300
student 379 2.2 0.0 10888 4296 pts/0 R+ 08:40 0:00 ps -u
$ kill -CONT 366
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 358 0.2 0.0 7612 2948 pts/0 Ss 08:39 0:00 bash
student 386 50.0 0.0 10888 4396 pts/0 R+ 08:40 0:00 ps -u
[1]+ Terminated sleep 300بعد kill 366 تبقى العملية في الجدول بالحالة T: فالعملية الموقوفة لا تستجيب للإشارة SIGTERM؛ وتبقى الإشارة معلقة. وبمجرد أن يسمح لها -CONT بالاستئناف، تعالج SIGTERM المعلقة وتصبح Terminated. أما kill -9 فلا ينتظر: التجربة نفسها مع yes تبين أن العملية الموقوفة تنتهي فورا.
$ yes > /dev/null &
[1] 387
$ kill -STOP 387
[1]+ Stopped yes > /dev/null
$ kill -9 387
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 358 0.1 0.0 8128 2548 pts/0 Ss 08:39 0:00 bash
student 400 0.0 0.0 10888 4420 pts/0 R+ 08:40 0:00 ps -u
[1]+ Killed yes > /dev/nullمثال محلول 7: الزومبي
السؤال. ينشئ الأمر (sleep 1 & exec sleep 60) & عملية أب (parent) هي sleep 60، لها عملية ابن (child) هي sleep 1. تنتهي العملية الابن بعد ثانية واحدة، لكن sleep لا يجمع أبناءه أبدا، فتبقى العملية الابن الميتة في الجدول. توقع ما يفعله kill -9 بالزومبي، وما يحدث عند قتل العملية الأب.
الإجابة.
$ (sleep 1 & exec sleep 60) &
[1] 188
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 178 1.1 0.0 7608 4288 pts/0 Ss 08:07 0:00 bash
student 188 0.0 0.0 5688 2136 pts/0 S 08:07 0:00 sleep 60
student 189 0.0 0.0 0 0 pts/0 Z 08:07 0:00 [sleep] <defunct>
student 190 0.0 0.0 10888 4404 pts/0 R+ 08:07 0:00 ps -u
$ kill -9 189
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 178 0.9 0.0 7608 4288 pts/0 Ss 08:07 0:00 bash
student 188 0.0 0.0 5688 2136 pts/0 S 08:07 0:00 sleep 60
student 189 0.0 0.0 0 0 pts/0 Z 08:07 0:00 [sleep] <defunct>
student 197 0.0 0.0 10888 4388 pts/0 R+ 08:07 0:00 ps -u
$ kill 188
$ ps -u
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 178 0.6 0.0 7608 4276 pts/0 Ss 08:07 0:00 bash
student 204 0.0 0.0 10888 4308 pts/0 R+ 08:07 0:00 ps -u
[1]+ Terminated ( sleep 1 & exec sleep 60 )العملية الابن 189 زومبي: حالتها Z، وموسومة بأنها defunct، ولا تستخدم أي ذاكرة. لا يغير kill -9 189 شيئا، لأن العملية ميتة بالفعل؛ ولم يبق منها إلا مدخلها في الجدول، ينتظر أن تجمعه العملية الأب. وعندما تنتهي العملية الأب 188 يختفي المدخل معها.
لإيجاد العملية الأب لعملية ما، اطلب من ps العمود PPID (معرف العملية الأب، parent process ID)؛ ويختار الخيار -o الأعمدة. ومن تشغيل آخر للأمر نفسه:
$ (sleep 1 & exec sleep 60) &
[1] 896
$ ps -o pid,ppid,stat,cmd
PID PPID STAT CMD
889 888 Ss bash
896 889 S sleep 60
897 896 Z [sleep] <defunct>
899 889 R+ ps -o pid,ppid,stat,cmdقيمة PPID للزومبي 897 هي 896: فعمليتها الأب هي sleep 60، وهي العملية التي تنهيها. ولا يحتوي ps -u العمود PPID، فاستخدم هذه الصيغة كلما احتجت إلى العملية الأب.
تفاعلي: محاكي جدول العمليات
افتح محاكي جدول العمليات بملء الشاشة. اضغط تشغيل لجولة موجهة في كل الحالات أعلاه، أو ابدأ العمليات بنفسك، واختر سطرا وأرسل إليه الإشارات. ويتبع المحاكي سلوك التشغيلات الحقيقية في هذه الصفحة: kill ينهي العملية العادية، وstubborn.sh يتجاهله، والعملية الموقوفة تحتفظ بالإشارة SIGTERM حتى تستأنف، والزومبي تتجاهل كل شيء، ولا يستطيع خفض قيمة اللطف إلا sudo.
الجزء 4: الأولويات بالأمرين nice وrenice
قيمة اللطف
يستطيع لينكس المفاضلة بين العمليات. وتسمى قيمة الأولوية للعملية قيمة اللطف. ويعطي نص المساعدة للأمر nice مداها:
$ nice --help | head -4
Usage: nice [OPTION] [COMMAND [ARG]...]
Run COMMAND with an adjusted niceness, which affects process scheduling.
With no COMMAND, print the current niceness. Niceness values range from
-20 (most favorable to the process) to 19 (least favorable to the process).- تتراوح قيمة اللطف من
-20(الأكثر تفضيلا) إلى19(الأقل تفضيلا). والقيمة الافتراضية0. NI، العمود الرابع فيtop، هو قيمة اللطف.- لبدء عملية بقيمة لطف غير الافتراضية:
nice -n [value] [command]. - لتغيير قيمة لطف عملية تعمل بالفعل:
renice [value] -p PID.
$ nice -n 10 sleep 300 &
[1] 32
$ top -b -n 1 -p 32
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
32 student 30 10 5688 1932 1824 S 0.0 0.0 0:00.00 sleep
$ renice 15 -p 32
32 (process ID) old priority 10, new priority 15لا يظهر هنا من خرج top إلا سطر عناوين الأعمدة وسطر العملية (أما أسطر الملخص الخمسة فمحذوفة). ويسمي renice قيمة اللطف "أولوية" في رسالته: القديمة 10، والجديدة 15.
مثال محلول 8: من NI إلى PR
السؤال. كل سطر من أسطر top في هذا الدرس العملي يخضع لقاعدة واحدة بين NI وPR: 0 و20، و10 و30. توقع PR بعد renice 15، وبعد sudo renice 5. (الجزء الأول من الحل مأخوذ من تشغيل ثان للخطوات نفسها، ولذلك يختلف معرف العملية فيه.)
الإجابة. القاعدة هي
PR = 20 + NIحيث NI قيمة اللطف وPR أولوية الجدولة التي يعرضها top. يعطي renice 15 القيمة PR = 20 + 15 = 35، ويعطي sudo renice 5 القيمة PR = 20 + 5 = 25، وهذا ما طبعه top:
$ renice 15 -p 8751
8751 (process ID) old priority 10, new priority 15
$ top -b -n 1 -p 8751 | tail -2
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
8751 student 35 15 5688 2088 1980 S 0.0 0.0 0:00.00 sleep
$ sudo renice 5 -p 32
[sudo] password for student:
32 (process ID) old priority 15, new priority 5
$ top -b -n 1 -p 32
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
32 student 25 5 5688 344 236 S 0.0 0.0 0:00.00 sleepمثال محلول 9: خفض قيمة اللطف
السؤال. قيمة لطف العملية 15. ونطلب 5 بصفتنا المستخدم student. توقع الرد، ثم نفذ الطلب نفسه مع sudo.
الإجابة.
$ renice 5 -p 32
renice: failed to set priority for 32 (process ID): Permission denied
$ sudo renice 5 -p 32
[sudo] password for student:
32 (process ID) old priority 15, new priority 5يستطيع المستخدم العادي رفع قيمة لطف عمليته (نجح الانتقال من 10 إلى 15)، فيجعلها ألطف مع العمليات الأخرى، لكنه لا يستطيع خفضها: Permission denied. أما sudo فيشغل الأمر بصفة المستخدم الخارق (superuser)، أي الجذر (root)، الذي يستطيع ذلك. والقاعدة نفسها تمنع المستخدم العادي من بدء عملية بقيمة أقل من 0:
$ nice -n -5 sleep 1
nice: cannot set niceness: Permission deniedالجزء 5: ما معنى DevOps
فريقان وجدار
منذ البداية، كان لتطوير البرمجيات قسمان:
| الفريق | عمله |
|---|---|
| التطوير (Development) | يخطط للنظام ويصممه ويبنيه من الصفر |
| التشغيل (Operations) | يختبر ما يطور وينفذه، ويرسل الملاحظات (feedback) عن الأخطاء وإعادة العمل |
كثيرا ما كان فريق التطوير خاملا، ينتظر ملاحظات فريق التشغيل. وأحيانا كان قد انتقل إلى المشروع التالي بينما ما زال فريق التشغيل يرسل تقاريره عن الشيفرة (code) القديمة، فكان إغلاق المشروع يستغرق أسابيع أو حتى شهورا. ويسأل DevOps عما يحدث إذا اجتمع القسمان وعملا متعاونين: فينكسر "جدار الارتباك" (wall of confusion) بينهما. ورمز DevOps علامة اللانهاية: مسار مستمر من تحسين الكفاءة ونشاط دائم. فتتكيف الشركات أسرع مع التحديثات، وتسلم الفرق بسرعة، ويكون النشر أكثر اتساقا وسلاسة.
دورة حياة DevOps
ينفذ DevOps على مراحل، تساعد الأدوات في كل منها:
| المرحلة | ما يحدث | أمثلة على الأدوات |
|---|---|---|
| التخطيط (Plan) | يخطط الفريق للأهداف التي سيسلمها للعميل | |
| البرمجة (Code) | يعمل الجميع على الشيفرة نفسها؛ وتخزن الإصدارات في مستودع (repository) وتدمج عند الحاجة (التحكم في الإصدارات، version control) | Git |
| البناء (Build) | تحول الشيفرة إلى برنامج قابل للتنفيذ | Maven، Gradle |
| الاختبار (Test) | يختبر البرنامج المبني بحثا عن الأخطاء، يدويا وآليا | Selenium |
| النشر (Deploy) | تنتقل الشيفرة المختبرة إلى بيئة العمل | Ansible، Docker، Kubernetes |
| المراقبة (Monitor) | يراقب المنتج باستمرار؛ وتعود الملاحظات إلى التخطيط | Nagios |
التكامل المستمر (continuous integration) يربط المراحل معا: يرسل Jenkins الشيفرة للبناء والاختبار، فإذا اجتازت الاختبارات أرسلت للنشر.
وتعمل بهذه الطريقة شركات مثل Amazon وNetflix وWalmart وFacebook وAdobe. ففي عام 2014 قدرت كلفة ساعة واحدة من التوقف عن الخدمة (downtime) على Netflix بنحو 200,000 دولار. فبنت Netflix مجموعة من الأدوات اسمها Simian Army، تظل تحدث أعطالا في بيئتها دون أن تؤثر في المستخدمين، مما دفع مطوريها إلى بناء نظام لا ينهار عندما يتعطل شيء فيه.
مثال محلول 10: طابق الأداة
السؤال. طابق كل أداة مع مرحلتها: Git، Selenium، Docker، Nagios، Jenkins.
الإجابة. Git: البرمجة (التحكم في الإصدارات). Selenium: الاختبار (الاختبار الآلي، automation testing). Docker: النشر، مع Ansible وKubernetes. Nagios: المراقبة. Jenkins: التكامل المستمر، يرسل الشيفرة للبناء والاختبار.
لماذا تهم أوامر لينكس في DevOps
تشغل معظم المؤسسات بيئاتها على لينكس، وأدوات إدارة الإعدادات (configuration management) مثل Chef وPuppet وAnsible توجد عقدها الرئيسية على لينكس. وبضعة أوامر أساسية تمكن المطور من التحقيق في سبب عمل تطبيق على جهاز وتعطله على جهاز آخر، ومن وصف المشكلة لمديري الأنظمة. والأوامر أدناه تعمل بالطريقة نفسها على جهاز تطوير، وعلى آلة افتراضية، وداخل حاوية (container).
الجزء 6: مجموعة أوامر DevOps
الأمر sudo: شغل أمرا واحدا بصفة الجذر
يشغل sudo ذلك الأمر وحده بصلاحيات الجذر (المستخدم الخارق). ويطلب كلمة مرورك أنت في المرة الأولى.
| الأمر | ما يفعله |
|---|---|
sudo useradd -m NAME | يضيف مستخدما جديدا (-m ينشئ المجلد الرئيسي، home folder) |
sudo passwd NAME | ينشئ كلمة مرور للمستخدم |
sudo groupadd NAME | يضيف مجموعة (group) جديدة |
sudo usermod -g GROUP NAME | يعين المجموعة الأساسية (primary group) للمستخدم |
sudo userdel NAME | يحذف المستخدم |
sudo groupdel NAME | يحذف المجموعة |
$ sudo groupadd devops
[sudo] password for student:
$ sudo useradd -m deploy
$ sudo usermod -g devops deploy
$ id deploy
uid=1002(deploy) gid=1002(devops) groups=1002(devops)
$ sudo passwd deploy
New password:
Retype new password:
passwd: password updated successfullyالأمر id: معرفات المستخدم والمجموعة
يطبع id اسم المستخدم الحالي ومعرفه، ومجموعته الأساسية، وكل مجموعاته، أو ذلك كله لمستخدم آخر عندما تسميه (id deploy أعلاه).
$ id
uid=1001(student) gid=1001(student) groups=1001(student),27(sudo)
$ id -u
1001
$ id -g
1001
$ id -G
1001 27
$ id -Gn
student sudo| الخيار | ما يطبعه |
|---|---|
-u | معرف المستخدم الفعال (effective user ID) فقط |
-g | معرف المجموعة الفعال فقط |
-G | كل معرفات المجموعات |
-n | الأسماء بدلا من الأرقام (مع -u أو -g أو -G) |
ينتمي student إلى المجموعة sudo: وهذا ما يسمح له باستخدام sudo.
الأمر chown: تغيير المالك
لكل ملف مالك (owner) ومجموعة، يظهران في العمودين 3 و4 من خرج ls -l. ويغيرهما الأمر chown [OWNER][:[GROUP]] FILE. وإعطاء ملف لشخص آخر يحتاج إلى sudo:
$ ls -l servers.txt
-rw-r--r-- 1 student student 105 Sep 25 08:03 servers.txt
$ sudo chown deploy servers.txt
$ ls -l servers.txt
-rw-r--r-- 1 deploy student 105 Sep 25 08:03 servers.txt
$ sudo chown root:devops servers.txt
$ ls -l servers.txt
-rw-r--r-- 1 root devops 105 Sep 25 08:03 servers.txt(بعد ذلك أعدنا الملف بالأمر sudo chown student:student servers.txt، وحذفنا المستخدم والمجموعة التجريبيين بالأمرين sudo userdel -r deploy وsudo groupdel devops.)
الأوامر ls وcat وchmod من جديد
ربما تعرف هذه الأوامر بالفعل؛ وتضيف قائمة DevOps بعض الخيارات:
ls -aيعرض العناصر المخفية أيضا؛ وls -lيعطي التنسيق المطول بالأذونات (permissions) والمالك والطابع الزمني (time stamp).cat -nيرقم كل الأسطر، وcat -bالأسطر غير الفارغة فقط، وcat -sيدمج الأسطر الفارغة المتكررة في سطر واحد، وcat -Eيعرض$في نهاية كل سطر.chmodيضبط الأذونات بالأرقام:4للقراءة، و2للكتابة، و1للتنفيذ، و0لا شيء، ورقم واحد لكل من المالك والمجموعة والآخرين.
$ cat -b notes.txt
1 deploy steps
2 build the code
3 test the code
4 ship it
$ cat -s notes.txt
deploy steps
build the code
test the code
ship it
$ cat -n notes.txt
1 deploy steps
2
3
4
5 build the code
6 test the code
7
8 ship it
$ cat -E notes.txt
deploy steps$
$
$
$
build the code$
test the code$
$
ship it$
$ ls -l stubborn.sh
-rwxr-xr-x 1 student student 102 Sep 25 08:03 stubborn.sh
$ chmod 750 stubborn.sh
$ ls -l stubborn.sh
-rwxr-x--- 1 student student 102 Sep 25 08:03 stubborn.sh750 تعني 7 = 4 + 2 + 1 (قراءة وكتابة وتنفيذ) للمالك، و5 = 4 + 1 (قراءة وتنفيذ) للمجموعة، و0 (لا شيء) للآخرين: rwxr-x---.
الأمر grep: البحث داخل الملفات
يبحث grep عن كلمة في ملف، مثل Ctrl+F لكن في سطر الأوامر (command line)، ويطبع الأسطر المطابقة.
| الخيار | ما يعيده |
|---|---|
-n | الأسطر المطابقة مع أرقامها |
-i | المطابقات بغض النظر عن حالة الأحرف (كبيرة أو صغيرة) |
-c | عدد الأسطر المطابقة |
-v | الأسطر التي لا تطابق |
$ grep ERROR app.log
2026-09-25 09:02:30 ERROR web2 cannot connect to db1
2026-09-25 09:02:35 ERROR web2 cannot connect to db1
2026-09-25 09:07:02 ERROR web1 out of memory
$ grep -n ERROR app.log
4:2026-09-25 09:02:30 ERROR web2 cannot connect to db1
6:2026-09-25 09:02:35 ERROR web2 cannot connect to db1
10:2026-09-25 09:07:02 ERROR web1 out of memory
$ grep -c ERROR app.log
3مثال محلول 11: grep -i وgrep -v
السؤال. توقع عدد الأسطر التي يطبعها grep info app.log، وعدد الأسطر التي يطبعها grep -i info app.log، والرقم الذي يطبعه grep -c -v INFO app.log.
الإجابة.
$ grep info app.log
2026-09-25 09:03:00 info web2 connected to db1
$ grep -i info app.log
2026-09-25 09:00:01 INFO web1 service started on port 8080
2026-09-25 09:00:05 INFO db1 connection pool ready
2026-09-25 09:02:31 INFO web2 retrying connection
2026-09-25 09:03:00 info web2 connected to db1
2026-09-25 09:06:10 INFO web1 deploy version 2.4 finished
$ grep -v INFO app.log
2026-09-25 09:01:12 WARN web1 slow response 1200 ms
2026-09-25 09:02:30 ERROR web2 cannot connect to db1
2026-09-25 09:02:35 ERROR web2 cannot connect to db1
2026-09-25 09:03:00 info web2 connected to db1
2026-09-25 09:05:44 WARN db1 disk usage 85 percent
2026-09-25 09:07:02 ERROR web1 out of memory
$ grep -c -v INFO app.log
6عدد الأسطر التي يجدها grep info هو 1: فحالة الأحرف مهمة، والسطر 7 وحده فيه info بأحرف صغيرة. ومع -i تطابق أسطر INFO الأربعة أيضا، فيصبح العدد 5. أما -v INFO فيبقي الأسطر التي ليس فيها INFO بأحرف كبيرة: سطرا WARN، وأسطر ERROR الثلاثة، وسطر info بالأحرف الصغيرة، أي 6.
الأمر sort: ترتيب الأسطر
يرتب sort الأسطر أبجديا أو عدديا. ويعكس -r الترتيب، ويرتب -n بحسب القيمة العددية، ويتجاهل -f حالة الأحرف.
مثال محلول 12: sort وsort -n
السؤال. توقع خرج sort ports.txt وsort -n ports.txt.
الإجابة.
$ sort ports.txt
22
3306
443
5432
80
8080
$ sort -n ports.txt
22
80
443
3306
5432
8080يقارن sort وحده الأسطر بوصفها نصوصا، حرفا بحرف، ولذلك يأتي 3306 قبل 443 (لأن 3 قبل 4)، ويأتي 80 بعد 5432. أما -n فيقارنها بوصفها أرقاما. ويعكس -r أيا من الترتيبين:
$ sort -r servers.txt
web2,alexandria,8080,4
web1,cairo,8080,4
db1,mansoura,5432,16
cache1,cairo,6379,8
backup1,mansoura,22,32في أوبونتو مع إعداد اللغة الإنجليزية، يضع sort وحده الكلمة التي تبدأ بحرف كبير بجوار صيغتها بالأحرف الصغيرة، ولذلك لا يغير -f شيئا هنا:
$ sort hosts.txt
cache1
db1
DB2
web1
Web3
$ sort -f hosts.txt
cache1
db1
DB2
web1
Web3الأمر tail: نهاية الملف
يطبع tail الأسطر الأخيرة من الملف، وافتراضيا آخر 10 أسطر. والسجلات تنمو من أسفل، ولذلك تكون أحدث الأحداث في النهاية.
$ tail -n 3 app.log
2026-09-25 09:05:44 WARN db1 disk usage 85 percent
2026-09-25 09:06:10 INFO web1 deploy version 2.4 finished
2026-09-25 09:07:02 ERROR web1 out of memory
$ tail -3 app.log
2026-09-25 09:05:44 WARN db1 disk usage 85 percent
2026-09-25 09:06:10 INFO web1 deploy version 2.4 finished
2026-09-25 09:07:02 ERROR web1 out of memory
$ tail -n +9 app.log
2026-09-25 09:06:10 INFO web1 deploy version 2.4 finished
2026-09-25 09:07:02 ERROR web1 out of memory
$ tail -c 20 app.log
web1 out of memoryيطبع -n 3 (أو الصيغة المختصرة -3) آخر 3 أسطر، ويطبع -n +9 (أو +9) من السطر 9 حتى النهاية، ويطبع -c 20 آخر 20 بايتا: 19 حرفا مرئيا مع حرف السطر الجديد (newline).
الأمر cut: اختيار الأعمدة
يستخرج cut جزءا من كل سطر: -c يختار الأحرف، و-d يحدد الفاصل (delimiter)، و-f يختار الحقول (fields).
$ cut -c1-2 servers.txt
we
db
we
ca
ba
$ cut -d , -f 1 servers.txt
web1
db1
web2
cache1
backup1
$ cut -d , -f 1,3 servers.txt
web1,8080
db1,5432
web2,8080
cache1,6379
backup1,22الأمر tr: ترجمة الأحرف
يترجم tr الأحرف أو يحذفها. ويقرأ دخله (input) من أنبوب (أو من ملف معاد توجيهه)، لا من اسم ملف.
| الخيار | ما يفعله |
|---|---|
(بلا خيار) tr SET1 SET2 | يضع مكان كل حرف من SET1 الحرف المقابل له في SET2 |
-d | يحذف الأحرف الواردة في مجموعة الأحرف الأولى |
-s | يدمج الأحرف المتكررة في حرف واحد |
-c | يعمل على الأحرف غير الواردة في مجموعة الأحرف |
$ cat servers.txt | tr a-z A-Z
WEB1,CAIRO,8080,4
DB1,MANSOURA,5432,16
WEB2,ALEXANDRIA,8080,4
CACHE1,CAIRO,6379,8
BACKUP1,MANSOURA,22,32
$ echo "web1 db1 cache1" | tr -s " "
web1 db1 cache1
$ echo "web1 web2 db1" | tr -d 0-9
web web dbالأمر sed: تحرير تيار من النص
يحرر sed النص دون فتح محرر. ويضع s/old/new/ النص الجديد مكان أول تطابق في كل سطر؛ وإضافة g في النهاية تفعل ذلك مع كل التطابقات.
مثال محلول 13: الأمر sed لا يغير الملف
السؤال. بعد sed 's/8080/9090/' servers.txt، توقع ما يعرضه cat servers.txt.
الإجابة.
$ sed 's/8080/9090/' servers.txt
web1,cairo,9090,4
db1,mansoura,5432,16
web2,alexandria,9090,4
cache1,cairo,6379,8
backup1,mansoura,22,32
$ cat servers.txt
web1,cairo,8080,4
db1,mansoura,5432,16
web2,alexandria,8080,4
cache1,cairo,6379,8
backup1,mansoura,22,32الملف لم يتغير: يطبع sed نسخة محررة ويترك الملف كما هو. ويهم الخيار g عندما يحتوي السطر أكثر من تطابق واحد:
$ echo "8080 to 8080" | sed 's/8080/9090/'
9090 to 8080
$ echo "8080 to 8080" | sed 's/8080/9090/g'
9090 to 9090الأمر diff: المقارنة بين ملفين
يطبع diff الأسطر المختلفة بين ملفين.
مثال محلول 14: اقرأ خرج diff
السؤال. اشرح كل سطر من خرج diff config.old config.new.
الإجابة.
$ diff config.old config.new
1c1
< port=8080
---
> port=9090
3c3
< debug=true
---
> debug=false
4a5
> timeout=301c1: يجب تغيير السطر 1 من الملف الأول إلى السطر 1 من الملف الثاني: أصبحport=8080هوport=9090.3c3: تغير السطر 3: أصبحdebug=trueهوdebug=false.4a5: بعد السطر 4 من الملف الأول، أضف السطر 5 من الملف الثاني:timeout=30.- الأسطر التي تبدأ بعلامة أصغر من تأتي من الملف الأول، والأسطر التي تبدأ بعلامة أكبر من تأتي من الملف الثاني، ويفصل
---بينها. السطر 2 (workers=4) والسطر 4 (log=...) متساويان، ولذلك لا يطبعان. والملفان المتطابقان لا يطبع لهما شيء:
$ diff config.old config.oldالأمر find: التجول في شجرة المجلدات
يتجول find في مجلد وكل ما تحته، ويجد الملفات بالاسم، ورقم العقدة الفهرسية (inode number)، والمالك، والتواريخ، والأذونات. ويستطيع أيضا تشغيل أمر على كل ملف يجده.
| الخيار | ما يفعله |
|---|---|
-name PATTERN | الملفات التي يطابق اسمها النمط |
-inum N | الملف الذي رقم عقدته الفهرسية N (يعرضه ls -i) |
-links N | الملفات التي لها N من الروابط |
-exec CMD | يشغل CMD على كل ملف يجده (يوضع الملف مكان القوسين المعقوصين) |
-ok CMD | مثل -exec، لكنه يسألك أولا |
لهذا المثال وضعت نسختان من السجل في مجلد اسمه logs:
$ find . -name "*.log"
./app.log
./logs/old/web-0924.log
./logs/web.log
$ find logs -name "*.log" -exec ls -l {} \;
-rw-r--r-- 1 student student 519 Sep 25 08:19 logs/old/web-0924.log
-rw-r--r-- 1 student student 519 Sep 25 08:19 logs/web.log
$ ls -i app.log
4456513 app.log
$ find . -inum 4456513
./app.log
$ find . -name "*.log" -ok rm {} \;
< rm ... ./app.log > ? n
< rm ... ./logs/old/web-0924.log > ? n
< rm ... ./logs/web.log > ? y
$ find . -name "*.log"
./app.log
./logs/old/web-0924.logسأل الأمر الأخير قبل كل حذف، ولم يحذف إلا logs/web.log (الذي كانت الإجابة عنه y).
الأمر dd: نسخ البايتات وتحويلها
ينسخ dd البيانات كتلة (block) بعد كتلة، ويستطيع تحويلها في أثناء النسخ. ولأن الأجهزة تظهر في لينكس على هيئة ملفات، يستطيع dd أيضا القراءة منها أو الكتابة إليها: ويستخدم في مهام مثل النسخ الاحتياطي لمنطقة الإقلاع في القرص، أو الحصول على كمية ثابتة من البيانات العشوائية.
$ dd if=/dev/zero of=disk.img bs=1M count=5
5+0 records in
5+0 records out
5242880 bytes (5.2 MB, 5.0 MiB) copied, 0.013896 s, 377 MB/s
$ ls -l disk.img
-rw-r--r-- 1 student student 5242880 Sep 25 08:28 disk.img
$ dd if=/dev/urandom of=key.bin bs=16 count=1
1+0 records in
1+0 records out
16 bytes copied, 0.000774319 s, 20.7 kB/s
$ ls -l key.bin
-rw-r--r-- 1 student student 16 Sep 25 08:28 key.bin
$ dd if=servers.txt of=upper.txt conv=ucase
0+1 records in
0+1 records out
105 bytes copied, 0.00259888 s, 40.4 kB/s
$ cat upper.txt
WEB1,CAIRO,8080,4
DB1,MANSOURA,5432,16
WEB2,ALEXANDRIA,8080,4
CACHE1,CAIRO,6379,8
BACKUP1,MANSOURA,22,32if هو ملف الدخل، وof ملف الخرج، وbs حجم الكتلة، وcount عدد الكتل. وعدد البايتات المنسوخة هو
B = n × s = 5 × 1048576 = 5242880حيث B عدد البايتات المنسوخة، وn قيمة count، وs قيمة bs بالبايت (1M تساوي 1048576). ويعطي /dev/zero بايتات صفرية بلا نهاية، و/dev/urandom بايتات عشوائية بلا نهاية، ويحول conv=ucase الأحرف إلى أحرف كبيرة في أثناء النسخ. وتعني 0+1 records صفرا من الكتل الكاملة وكتلة واحدة جزئية: فالملف البالغ حجمه 105 بايتات كان أصغر من كتلة واحدة.
الأمران tar وgzip: الأرشفة والضغط
يحزم tar ملفات كثيرة في ملف أرشيف (archive) واحد، ومع z يضغط الأرشيف أيضا بالأمر gzip. والأحرف التي تلي tar هي خياراته: c ينشئ أرشيفا، وt يعرض ما بداخله، وx يستخرج، وz يمرر البيانات عبر gzip، وf يسمي ملف الأرشيف. ويختار -C المجلد الذي يستخرج إليه.
$ tar czf lab10.tar.gz app.log servers.txt notes.txt
$ ls -l app.log servers.txt notes.txt lab10.tar.gz
-rw-r--r-- 1 student student 519 Sep 25 10:31 app.log
-rw-r--r-- 1 student student 499 Sep 25 10:32 lab10.tar.gz
-rw-r--r-- 1 student student 54 Sep 25 10:31 notes.txt
-rw-r--r-- 1 student student 105 Sep 25 10:31 servers.txt
$ tar tzf lab10.tar.gz
app.log
servers.txt
notes.txt
$ mkdir restore
$ tar xzf lab10.tar.gz -C restore
$ ls restore
app.log notes.txt servers.txtتحتوي الملفات الثلاثة 519 + 105 + 54 = 678 بايتا، والأرشيف المضغوط 499. أما gzip وحده فيضغط ملفا واحدا ويستبدل به ملفا امتداده .gz؛ ويعكس gunzip ذلك:
$ gzip app.log
$ ls -l app.log*
-rw-r--r-- 1 student student 264 Sep 25 10:31 app.log.gz
$ gunzip app.log.gz
$ ls -l app.log*
-rw-r--r-- 1 student student 519 Sep 25 10:31 app.logصغر السجل من 519 إلى 264 بايتا: فأسطره تكرر كلمات كثيرة، والنص المتكرر ينضغط جيدا.
الأمران df وdu: مساحة القرص
يعرض df (اختصار disk free) الحجم والمساحة المستخدمة والمتاحة في كل نظام ملفات (file system)؛ ويعرض du (اختصار disk usage) المساحة التي يشغلها مجلد. ويطبع -h الأحجام بصيغة سهلة القراءة (K وM وG)، ويطبع du -s سطر ملخص واحدا بدلا من سطر لكل مجلد فرعي.
$ df -h /
Filesystem Size Used Avail Use% Mounted on
overlay 916G 822G 52G 95% /
$ du -h /var/log
40K /var/log/apt
304K /var/log
$ du -sh /var/log
304K /var/logيسأل df -h / عن نظام الملفات الذي يحوي / فقط: وهو ممتلئ بنسبة 95%، والمتبقي 52G. والقرص الممتلئ، مثل الذاكرة الممتلئة، سبب شائع لتعطل الخادم. وعلى آلتك الافتراضية يسمي العمود Filesystem قسما (partition) من القرص تحت /dev، لا overlay، أي نظام ملفات الحاوية. ويعرض du -h المجلد /var/log/apt، ثم /var/log نفسه، وحجمه 304K يشمل 40K لمجلده الفرعي.
الأمر free: الذاكرة
يعرض free مجموع الذاكرة ومساحة التبديل (swap) والمستخدم والحر منهما، والمخازن المؤقتة (buffers) التي تستخدمها النواة. وتختار -b و-k و-m و-g البايت أو الكيلوبايت أو الميغابايت أو الغيغابايت.
$ free -m
total used free shared buff/cache available
Mem: 31866 30491 398 471 2276 1375
Swap: 24575 24575 0
$ free -g
total used free shared buff/cache available
Mem: 31 29 0 0 2 1
Swap: 23 23 0كان الجهاز الذي شغلت عليه هذه الأوامر يعاني نقصا في الذاكرة: المتاح 1375 فقط من 31866، ومساحة التبديل مستخدمة بالكامل. وهذا أول ما تفحصه عندما يصبح تطبيق ما بطيئا.
الأمر history: الأوامر التي شغلتها
يعرض history الأوامر التي شغلتها، لكل منها رقم حدث (event number)؛ ويعرض history 5 آخر خمسة أوامر.
$ history 5
177 dd if=servers.txt of=upper.txt conv=ucase
178 cat upper.txt
179 free -m
180 free -g
181 history 5الأمر hostname: اسم الجهاز
يطبع hostname الاسم الذي يعرف به الجهاز على الشبكة.
$ hostname
ubuntu-labالأمر ifconfig: واجهات الشبكة
يعرض ifconfig (اختصار interface configuration، أي إعداد الواجهة) واجهات الشبكة (network interfaces) وعناوينها وعدادات حركة البيانات فيها؛ ويستخدم أيضا لتعيين عنوان أو لتفعيل واجهة أو تعطيلها. ويعرض -a كل الواجهات، حتى المعطلة منها، ويعرض -s قائمة مختصرة. وإذا قال أوبونتو عندك إن الأمر غير موجود، فثبته بالأمر sudo apt install net-tools.
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.4 netmask 255.255.0.0 broadcast 172.17.255.255
ether e6:b9:29:25:6c:0c txqueuelen 0 (Ethernet)
RX packets 43 bytes 7442 (7.4 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3 bytes 126 (126.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
$ ifconfig -s
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
eth0 1500 43 0 0 0 3 0 0 0 BMRU
lo 65536 0 0 0 0 0 0 0 0 LRUeth0 هي بطاقة الشبكة في الجهاز وعنوانها 172.17.0.4؛ وlo هي واجهة الاسترجاع (loopback)، 127.0.0.1، أي الجهاز يتحدث إلى نفسه (الاسم localhost).
الأمر ping: هل يمكن الوصول إلى الجهاز؟
يرسل ping حزم اختبار صغيرة (packets) إلى جهاز، ويبلغ عما إذا كانت كل حزمة تعود، وبأي سرعة: وهو أول فحص عندما يتعذر الوصول إلى خادم. ويتوقف -c 4 بعد 4 حزم؛ وبدونه يستمر ping حتى تضغط Ctrl+C.
$ ping -c 4 google.com
PING google.com (142.251.27.138) 56(84) bytes of data.
64 bytes from cv-in-f138.1e100.net (142.251.27.138): icmp_seq=1 ttl=109 time=47.4 ms
64 bytes from cv-in-f138.1e100.net (142.251.27.138): icmp_seq=2 ttl=109 time=49.8 ms
64 bytes from cv-in-f138.1e100.net (142.251.27.138): icmp_seq=3 ttl=109 time=46.8 ms
64 bytes from cv-in-f138.1e100.net (142.251.27.138): icmp_seq=4 ttl=109 time=46.7 ms
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 46.666/47.683/49.815/1.263 msيعطي كل سطر رد زمن الذهاب والعودة time بالمللي ثانية. ويقول الملخص إن الحزم الأربع (4) عادت كلها (0% packet loss)، بمتوسط نحو 47.7 مللي ثانية. ويعرض السطر الأول العنوان الذي ترجم إليه الاسم google.com.
الأمر telnet: الاتصال بجهاز بعيد
يتصل telnet بحاسوب آخر، أو بمنفذ عليه، لتشغيل البرامج وإدارته عن بعد. ويستخدمه DevOps للتحقق مما إذا كانت خدمة ما تستمع.
مثال محلول 15: هل الخدمة تعمل؟
السؤال. شغلت خدمة تجريبية على المنفذ 8080 في هذا الجهاز؛ ولا شيء يستمع على المنفذ 9090، ولا يوجد خادم telnet مثبت. توقع خرج telnet localhost وtelnet localhost 8080 وtelnet localhost 9090.
الإجابة.
$ telnet localhost
Trying ::1...
Connection failed: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
$ telnet localhost 8080
Trying ::1...
Connection failed: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
^]
telnet> quit
Connection closed.
$ telnet localhost 9090
Trying ::1...
Connection failed: Connection refused
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refusedتعني Connected to localhost أن شيئا يجيب على المنفذ 8080. وتعني Connection refused أنه لا شيء يستمع على ذلك المنفذ (وtelnet بلا منفذ يجرب المنفذ 23، أي خادم telnet). وللخروج من اتصال، اضغط Ctrl+] واكتب quit.
تفاعلي: بناء خط أنابيب
افتح باني خط الأنابيب (pipeline) بملء الشاشة. اختر نمطا للأمر grep وخياراته، وحقلا للأمر cut، ثم tr وsort وtail: فيكتب لك سطر الأوامر، ويمر تشغيل على الأنبوب مرحلة بعد مرحلة، ويشطب الأسطر التي تحذفها كل مرحلة. وقد تحققنا من خرجه مقابل الأوامر الحقيقية في كل التركيبات، وعددها 2352 تركيبة.
تمارين
نحو 30 دقيقة. حل التمارين من 1 إلى 3 على الورق، ثم تحقق من إجاباتك في آلتك الافتراضية (VM). وينفذ التمرين 4 في الآلة الافتراضية. والإجابات في النهاية.
التمرين 1: اقرأ الجدول
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
student 563 0.7 0.0 7608 4436 pts/0 Ss 09:03 0:00 bash
student 571 0.0 0.0 5688 2088 pts/0 S 09:03 0:00 sleep 500
student 572 0.0 0.0 5688 1984 pts/0 T 09:03 0:00 sleep 700
student 579 98.1 0.0 5688 1920 pts/0 R 09:03 0:03 yes
student 580 0.0 0.0 5688 2036 pts/0 S 09:03 0:00 sleep 90
student 581 0.0 0.0 0 0 pts/0 Z 09:03 0:00 [sleep] <defunct>
student 582 0.0 0.0 10888 4476 pts/0 R+ 09:03 0:00 ps -u- أي عملية موقوفة، وأيها تستخدم المعالج؟
- أي عملية زومبي؟ وكيف تزيلها من الجدول؟
- ماذا يحدث بعد
kill 572؟ وبعدkill -CONT 572الذي يليه؟
التمرين 2: الأولويات
- يبدأ
nice -n 19 sleep 100 &العملية ذات المعرف615. ما قيمتاNIوPRلها فيtop؟ - بصفتك
student:renice 10 -p 615. ماذا يحدث؟ sudo renice -20 -p 615. ما قيمتاNIوPRالآن؟- بصفتك
student:nice -n -5 sleep 1. ماذا يحدث؟
التمرين 3: سجل نشر
احفظ هذا باسم deploy.log:
09:10 OK build web1
09:12 FAIL test web1
09:15 OK build web2
09:16 ok test web2
09:20 FAIL deploy web2
09:25 OK deploy web1اكتب الأمر، وتوقع خرجه، لكل مهمة:
- كم سطرا يحتوي
FAIL؟ - كل الأسطر التي تحتوي
okبأي حالة أحرف، مع أرقام أسطرها. - المرحلة (الحقل الثالث) في كل سطر.
- الخوادم (الحقل الرابع) في أسطر
FAILفقط. - السجل وقد حل
RETRYمحلFAIL، دون تغيير الملف. - آخر سطرين (2).
- يحتوي
sizes.txtالأرقام120و15و7و1024و64، رقما في كل سطر. توقع خرجsort sizes.txtوsort -n -r sizes.txt. - يحتوي
db.oldالأسطرport=5432وuser=appوmax=100؛ ويحتويdb.newالأسطرport=5432وuser=adminوmax=100وssl=on. توقع خرجdiff db.old db.new.
التمرين 4: في آلتك الافتراضية
- أنشئ ملفات مجلد الدرس العملي، واجعل
stubborn.shقابلا للتشغيل بالأمرchmod +x stubborn.sh. - ابدأ
sleep 600 &و./stubborn.sh &، وجد معرفي العمليتين بالأمرps -u. - أوقف
sleepبالأمرkill -STOP، وافحص حالتها، واستأنفها بالأمرkill -CONT، ثم أنهها بالأمرkill. - حاول إنهاء
stubborn.shبالأمرkill. أي إشارة تنجح؟ - ابدأ
nice -n 5 sleep 600 &، واقرأPRوNIلها فيtop، ثم نفذ عليهاrenice 12واقرأهما من جديد. توقع القيم أولا. - شغل
grep ERROR app.log | cut -d " " -f 4 | sortوتحقق من النتيجة في باني خط الأنابيب. - شغل
idوfree -mوhistory 10، واشرح كل سطر من الخرج.
الإجابات
التمرين 1
- الموقوفة:
572(sleep 700، الحالةT). والتي تستخدم المعالج:579(yes، الحالةR،98.1%). 581([sleep]، الحالةZ، موسومة بأنها defunct). لا يستطيعkillولا حتىkill -9إزالتها، لأنها ميتة بالفعل. والحل إنهاء عمليتها الأب، التي يعرضهاps -o pid,ppid,stat,cmdفي العمودPPIDللزومبي:580(sleep 90). فيختفي مدخل الزومبي معها.- يرسل
kill 572الإشارة SIGTERM إلى عملية موقوفة: لا يحدث شيء ظاهر وتبقىT، محتفظة بالإشارة. ثم يسمح لهاkill -CONT 572بالاستئناف؛ فتعالج SIGTERM المعلقة وتبلغ الصدفة بأنهاTerminated(قارن بالمثال المحلول 6).
التمرين 2
$ nice -n 19 sleep 100 &
[1] 615
$ top -b -n 1 -p 615 | tail -2
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
615 student 39 19 5688 2132 2024 S 0.0 0.0 0:00.00 sleep
$ renice 10 -p 615
renice: failed to set priority for 615 (process ID): Permission denied
$ sudo renice -20 -p 615
[sudo] password for student:
615 (process ID) old priority 19, new priority -20
$ top -b -n 1 -p 615 | tail -2
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
615 student 0 -20 5688 2132 2024 S 0.0 0.0 0:00.00 sleep
$ nice -n -5 sleep 1
nice: cannot set niceness: Permission deniedNI = 19وPR = 20 + 19 = 39.Permission denied: فالقيمة10أقل من19، ولا يستطيع خفض قيمة اللطف إلا الجذر.NI = -20وPR = 20 - 20 = 0.nice: cannot set niceness: Permission denied؛ ومع ذلك يعمل الأمر بقيمة اللطف العادية.
التمرين 3
$ grep -c FAIL deploy.log
2
$ grep -n -i ok deploy.log
1:09:10 OK build web1
3:09:15 OK build web2
4:09:16 ok test web2
6:09:25 OK deploy web1
$ grep -v OK deploy.log
09:12 FAIL test web1
09:16 ok test web2
09:20 FAIL deploy web2
$ tail -n 2 deploy.log
09:20 FAIL deploy web2
09:25 OK deploy web1
$ cut -d " " -f 3 deploy.log
build
test
build
test
deploy
deploy
$ sed 's/FAIL/RETRY/' deploy.log
09:10 OK build web1
09:12 RETRY test web1
09:15 OK build web2
09:16 ok test web2
09:20 RETRY deploy web2
09:25 OK deploy web1
$ grep FAIL deploy.log | cut -d " " -f 4
web1
web2
$ sort sizes.txt
1024
120
15
64
7
$ sort -n -r sizes.txt
1024
120
64
15
7
$ diff db.old db.new
2c2
< user=app
---
> user=admin
3a4
> ssl=on
$ cat deploy.log | tr a-z A-Z
09:10 OK BUILD WEB1
09:12 FAIL TEST WEB1
09:15 OK BUILD WEB2
09:16 OK TEST WEB2
09:20 FAIL DEPLOY WEB2
09:25 OK DEPLOY WEB1grep -c FAIL deploy.log:2.grep -n -i ok deploy.log: الأسطر1و3و4و6. وبدون-iكان السطر4(ok) سيغيب.cut -d " " -f 3 deploy.log:build،test،build،test،deploy،deploy.grep FAIL deploy.log | cut -d " " -f 4:web1،web2.sed 's/FAIL/RETRY/' deploy.log؛ ويظلcat deploy.logبعده يعرضFAIL.tail -n 2 deploy.log: سطرا09:20و09:25.- يقارن
sortالنصوص:1024،120،15،64،7. ويقارنsort -n -rالأرقام، من الأكبر إلى الأصغر:1024،120،64،15،7. 2c2(أصبحuser=appهوuser=admin) و3a4(بعد السطر 3، أضفssl=on).
ويبين التشغيل أعلاه أيضا فخين: يبقي grep -v OK سطر ok بالأحرف الصغيرة، لأن حالة الأحرف مهمة بدون -i، ويحول tr a-z A-Z السجل كله إلى أحرف كبيرة.
التمرين 4
- يعرض
ls -lالحرفxفي أذونات المالك للملفstubborn.sh. - يعرض
ps -uالعمليتينsleep 600و/bin/bash ./stubborn.sh، لكل منهما معرفها. - يصبح
STATللعمليةsleepهوTبعد-STOP، ثمSمن جديد بعد-CONT، وتبلغ الصدفةTerminatedبعدkill. - يتجاهل السكربت
kill؛ وينجحkill -9وتبلغ الصدفةKilled. NI = 5وPR = 25؛ وبعدrenice 12:NI = 12وPR = 32.web1،web2،web2: خوادم أسطرERRORالثلاثة، مرتبة.id: معرف المستخدم، والمجموعة الأساسية، وكل المجموعات (ومنهاsudoإذا كان مسموحا لك باستخدامه).free -m: مجموع الذاكرة ومساحة التبديل والمستخدم والحر والمتاح منهما بالميغابايت.history 10: آخر عشرة أوامر لك مع أرقام أحداثها.