Linux: الفرسان الثلاثة لمعالجة النصوص — awk / sed / cut
إذا grep لـ"البحث"، فإن awk وsed وcut لـ"التغيير". cut يقطع الأعمدة، وawk يولّد تقارير بيانات، وsed يقوم بالاستبدال المجمّع — مع الأنابيب، يمكنها التعامل مع تقريبًا أي مهمة نصية.
📋 المتطلبات المسبقة: يجب إكمال
- الدرس 14: البحث في النص
1. ما ستتعلمه
- cut: استخراج أعمدة بالمحدد
- awk: معالجة أعمدة متقدمة
- sed: استبدال وحذف
- tr: ترجمة محارف
- diff: مقارنة ملفات
2. قصة معالجة ملف CSV
(1) نقطة الألم: ملف CSV يحتاج تحويل صياغة
تلقى شياو مينغ ملف CSV واحتاج استخراج العمودين 2 و5، وإزالة الأسطر الفارغة، وتغيير المحدد من فواصل إلى علامات جدولة.
(2) سلسلة أنبوب واحد تفعل كل شيء
cat data.csv | cut -d',' -f2,5 | sed '/^$/d' | tr ',' '\t' > output.tsv
cut -d',' -f2,5: تقسيم بفاصلة، أخذ العمودين 2 و5sed '/^$/d': حذف الأسطر الفارغةtr ',' '\t': استبدال الفواصل بعلامات جدولة> output.tsv: الإخراج لملف جديد
(3) الفائدة: معالجة بيانات بدون برمجة
تخطى شياو مينغ عناء فتح Excel أو كتابة سكريبت Python. أمر واحد، ومعالجة البيانات تمت.
3. نقاط المعرفة
(1) cut — تقطيع بالأعمدة
# تقسيم بمحدد
cut -d',' -f1,3 file.csv # محدد فاصلة، أخذ العمودين 1 و3
cut -d: -f1 /etc/passwd # محدد نقطتان، أخذ أسماء المستخدمين
> ℹ️ ملاحظة: `cut` مناسب لاستخراج أعمدة بسيط (محدد ثابت، أرقام أعمدة ثابتة). للسيناريوهات التي تتطلب تصفية شرطية أو حسابات أو تنسيقًا، استخدم `awk` بدلًا من ذلك. مثلًا، `awk -F: '$3 >= 1000 {print $1}' /etc/passwd` يمكنه تصفية المستخدمين ذوي UID ≥ 1000 — `cut` لا يستطيع ذلك.
# تقسيم بموضع المحرف
cut -c1-5 file.txt # أخذ المحارف 1-5
cut -c1,3,5 file.txt # أخذ المحارف 1 و3 و5
(2) awk — مولّد تقارير البيانات
awk لغة معالجة نصوص كاملة. نمطه الأساسي:
awk 'pattern {action}' file
متغيرات awk المدمجة:
| المتغير | المعنى |
|---|---|
$0 |
السطر بالكامل |
$1 |
الحقل الأول |
$2 |
الحقل الثاني |
NF |
عدد الحقول |
NR |
رقم السطر |
FS |
فاصل حقول الإدخال (افتراضي: مسافة/جدولة) |
OFS |
فاصل حقول الإخراج (افتراضي: مسافة) |
$0 هو السطر كاملًا، و$1/$2/$3 هي الحقول 1/2/3، وNR رقم السطر، وNF عدد الحقول ($NF هو الحقل الأخير). مع -F: لتحديد محدد، يمكنك التعامل مع معظم مهام استخراج النصوص.
# استخدام أساسي
awk '{print $1}' file.txt # طباعة العمود 1
awk '{print $1, $3}' file.txt # طباعة العمودين 1 و3
awk '{print NR, $0}' file.txt # طباعة رقم السطر والسطر كاملًا
awk '{print $NF}' file.txt # طباعة العمود الأخير
awk -F: '{print $1}' /etc/passwd # تحديد النقطتين كمحدد
# مطابقة الأنماط
awk '/error/ {print}' log.txt # معالجة الأسطر التي تحتوي error فقط
awk '$3 > 100 {print $1, $3}' data.txt # إخراج فقط عندما العمود 3 > 100
# تجميع
awk '{sum += $1} END {print sum}' numbers.txt # مجموع
awk '{count++} END {print count}' file.txt # عدّ
(3) sed — المحرر الانسيابي
# استبدال
sed 's/old/new/' file.txt # استبدال أول ظهور في كل سطر
sed 's/old/new/g' file.txt # استبدال شامل
sed 's/old/new/2' file.txt # استبدال الظهور الثاني فقط في كل سطر
sed 's/old/new/g' file.txt > new.txt # إخراج لملف جديد
sed -i 's/old/new/g' file.txt # تعديل في المكان (يعدّل الملف مباشرة)
sed -i.bak 's/old/new/g' file.txt # نسخ احتياطي للأصل كـfile.txt.bak
> 💡 نصيحة: `sed -i` يعدّل الملف في مكانه بدون إمكانية التراجع. عاين النتيجة أولًا بدون `-i`: `sed 's/old/new/g' file.txt`، ثم أضف `-i` بعد التأكيد. أو استخدم `sed -i.bak` لإنشاء نسخة احتياطية تلقائيًا.
# حذف
sed '/pattern/d' file.txt # حذف أسطر تطابق النمط
sed '3d' file.txt # حذف السطر 3
sed '5,10d' file.txt # حذف الأسطر 5-10
sed '/^$/d' file.txt # حذف الأسطر الفارغة
# طباعة
sed -n '5,10p' file.txt # طباعة الأسطر 5-10 فقط
sed -n '/pattern/p' file.txt # طباعة الأسطر المطابقة فقط
(4) tr — ترجمة المحارف
# تحويل حالة الأحرف
echo "hello" | tr 'a-z' 'A-Z' # HELLO
cat file.txt | tr '[:lower:]' '[:upper:]'
# استبدال وحذف
echo "a,b,c" | tr ',' ' ' # a b c
echo "hello world" | tr -s ' ' # hello world (ضغط المسافات المتكررة)
echo "hello123" | tr -d '0-9' # hello (حذف الأرقام)
echo "abc123" | tr -d '[:digit:]' # abc (حذف الأرقام)
# تحويل نهايات الأسطر (ويندوز ↔ يونكس)
tr -d '\r' < win.txt > unix.txt # إزالة CR الخاص بويندوز
tr '\n' ',' < list.txt # استبدال الأسطر الجديدة بفواصل
(5) diff — مقارنة الملفات
diff file1.txt file2.txt # مقارنة أساسية
diff -u file1.txt file2.txt # صياغة موحدة (أكثر قابلية للقراءة)
diff -i file1.txt file2.txt # تجاهل حالة الأحرف
diff -w file1.txt file2.txt # تجاهل اختلافات المسافات
diff -r dir1/ dir2/ # مقارنة تكرارية للدلائل
(6) ▶ مثال: تقطيع أعمدة بـcut
# استخراج اسم المستخدم وصدفة الولوج من /etc/passwd
cut -d: -f1,7 /etc/passwd | head -5
# root:/bin/bash
# daemon:/usr/sbin/nologin
# bin:/usr/sbin/nologin
# أخذ العمود 5 (حجم الملف) من مخرجات ls -l
ls -la | tr -s ' ' | cut -d' ' -f5 | head -5
الإخراج:
TEXTroot:/bin/bash daemon:/usr/sbin/nologin bin:/usr/sbin/nologin sys:/usr/sbin/nologin sync:/usr/sbin/nologin 4096 4096 1234 5678 910
(7) ▶ مثال: معالجة أعمدة بـawk
# طباعة اسم المستخدم والدليل المنزلي
awk -F: '{print $1, "Home:", $6}' /etc/passwd | head -5
# إيجاد مستخدمين عاديين بUID أكبر من 1000
awk -F: '$3 >= 1000 {print $1, "(UID:" $3 ")"}' /etc/passwd
# حساب إجمالي حجم الملفات
ls -la | grep "^-" | awk '{sum += $5} END {print "Total:", sum/1024/1024, "MB"}'
# إخراج منسّق (printf)
ls -la | awk '{printf "%-20s %8s\n", $9, $5}'
الإخراج:
TEXTroot Home: /root daemon Home: /usr/sbin bin Home: /bin sys Home: /dev nobody Home: /nonexistent alice (UID:1000) bob (UID:1001) Total: 256.5 MB .bashrc 3771 .profile 220 .bash_history 1234
(8) ▶ مثال: استبدال مجموع بـsed
# استبدال localhost بـ127.0.0.1 في الملف
sed -i 's/localhost/127.0.0.1/g' config.txt
# تعليق الأسطر التي تبدأ بـlisten في ملف الإعدادات
sed -i '/^listen/s/^/#/' nginx.conf
# إدراج سطر جديد بعد السطر 2
sed '2a\New line inserted' file.txt
# استخراج الطوابع الزمنية من ملف السجل
sed -n 's/.*\[\(.*\)\].*/\1/p' access.log | head -5
الإخراج:
TEXT07/Jul/2026:10:15:30 +0000 07/Jul/2026:10:15:31 +0000 07/Jul/2026:10:15:32 +0000 07/Jul/2026:10:15:33 +0000 07/Jul/2026:10:15:34 +0000
(9) ▶ مثال: ترجمة محارف بـtr
# عدّ الكلمات في النص
cat file.txt | tr -s ' ' '\n' | sort | uniq -c | sort -rn | head -10
# تحويل قائمة لسطر واحد مفصول بفواصل
cat list.txt | tr '\n' ',' | sed 's/,$//'
# إزالة كل التعليقات والأسطر الفارغة من ملف إعدادات
grep -v "^#" config.txt | grep -v "^$" | tr -s '\n'
الإخراج:
TEXT42 the 28 and 25 linux 20 file 18 command 15 user 12 system 10 process 8 directory 6 shell apple,banana,cherry,date ServerName localhost Listen 80 DocumentRoot /var/www/html ErrorLog /var/log/apache2/error.log
(10) ▶ مثال: مقارنة ملفات بـdiff
# إنشاء نسختين
echo -e "apple\nbanana\norange" > v1.txt
echo -e "apple\nblueberry\norange" > v2.txt
# مقارنة
diff -u v1.txt v2.txt
# --- v1.txt
# +++ v2.txt
# @@ -1,3 +1,3 @@
# apple
# -banana
# +blueberry
# orange
(11) ▶ مثال شامل: تقرير مراقبة النظام
#!/bin/bash
# sys-report.sh - Generate system monitoring report
echo "========================================="
echo " System Monitoring Report"
echo " Generated at: $(date)"
echo "========================================="
echo ""
echo "1. Top 5 Processes by CPU Usage"
ps aux --sort=-%cpu | head -6 | awk '{printf "%-10s %-5s %-5s %s\n", $1, $2, $3, $11}'
echo ""
echo "2. Disk Usage"
df -h | grep "^/" | awk '{printf "%-20s %5s %5s %5s\n", $6, $2, $3, $5}'
echo ""
echo "3. Top 5 by Memory Usage"
ps aux --sort=-%mem | head -6 | awk '{printf "%-10s %-5s %-5s %s\n", $1, $2, $4, $11}'
echo ""
echo "4. Error Count in /var/log"
grep -ric "error" /var/log/*.log 2>/dev/null | grep -v ":0" | head -10
echo ""
echo "5. Listening Ports"
ss -tlnp | tail -n +2 | awk '{print $4, $1}' | sed 's/.*://'
echo ""
echo "========================================="
❓ أسئلة شائعة
س: ما الذي يجعل awk أقوى من cut؟ ج: cut يمكنه فقط تقطيع أعمدة بسيط (محدد ثابت). awk يدعم التصفية الشرطية والحسابات والإخراج المنسّق. awk لغة برمجة كاملة — تدعم المتغيرات والمصفوفات والحلقات والدوال. استخدم cut للسيناريوهات البسيطة، وawk للمعقدة.
س: هل
sed -iمحفوف بالمخاطر لتعديل الملف الأصلي؟ ج: نعم —sed -iيعدّل الملف في مكانه بدون إمكانية التراجع. عاين بدون-iأولًا، أو استخدمsed -i.bakلإنشاء نسخة احتياطية تلقائيًا. بعد تأكيد النتيجة، يمكنك حذف ملف.bak.
س: ما الفرق بين diff وvimdiff؟ ج: diff أداة سطر أوامر تُخرج نتائج مقارنة نصية. vimdiff هو وضع المقارنة المرئية لـvim بشاشة مقسومة جنبًا إلى جنب وتحرير تفاعلي. استخدم diff للمقارنات السريعة، وvimdiff للمعقدة.
س: هل يمكن لـtr التعامل مع المحارف الصينية؟ ج: يمكن، بحذر. المحارف الصينية مرمّزة بـUTF-8 متعددة البايت، وtr يعالج بالبايت، مما قد يقسم المحارف الصينية. للنصوص الصينية، استخدم
sedأو Python بدلًا من ذلك.
س: كيف أدمج أوامر معالجة نصوص متعددة بأكثر كفاءة؟ ج: المبدأ هو "تمريرة واحدة، عمليات متعددة." ضع التصفية البسيطة (grep) أولًا لتقليل حجم البيانات، ثم المعالجة الأثقل لاحقًا. تجنب إنشاء أنابيب وسيطة كثيرة في
cat file | grep | awk | sed | ....
📖 ملخص
cut -d',' -f1,3يقطع أعمدة بالمحددawk '{print $1}'يستخرج أعمدة، و-F:يحدد المحدد، و/pattern/يطابق، وENDيعمل في النهايةsed 's/old/new/g'استبدال شامل، و-iتعديل في المكان، و/^$/dحذف أسطر فارغةtr 'a-z' 'A-Z'تحويل حالة، و-dحذف، و-sضغط التكراراتdiff -u file1 file2مقارنة اختلافات الملفات
📝 تمارين
- أساسي (⭐): استخدم cut لاستخراج أسماء المستخدمين وUIDs (العمود 3) وصدفات الولوج من
/etc/passwd، ثم استخدم tr لتحويل محتوى/etc/hostnameلأحرف كبيرة - متوسط (⭐⭐): استخدم awk لتصفية ملفات أكبر من 1MB من مخرجات
ls -l، ثم استخدم sed لاستبدال رقم منفذ (8080 → 9090) مجمّعًا في ملف إعدادات، مع إنشاء نسخة احتياطية من الأصل - متقدم (⭐⭐⭐): أنشئ ملفي إعدادات مختلفين قليلًا، استخدم
diff -uلعرض الاختلافات، ثم اكتب سلسلة أنابيب لاستخراج كل أسطر الأخطاء من ملف سجل، وعدّ الأخطاء حسب الساعة، وأخرج أعلى 5 ساعات ذروة