grep وsed وawk: أمثلة لمعالجة النصوص في طرفية Linux
يبحث grep عن الأسطر حسب النمط (grep -rn error /var/log)، ويعدّل sed النص في التدفق أو داخل الملف (sed -i 's/old/new/g' file)، ويعمل awk على الأعمدة ويحسب (awk '{print $1}' access.log). وبالجمع بينها في خط أنابيب تغني عن كتابة سكريبت: يُصفّي grep الأسطر، ويُصحّح sed النص، ويستخرج awk الحقول ويجمعها.
grep وsed وawk ثلاث أدوات كلاسيكية في Linux لمعالجة النصوص. يبحث grep عن الأسطر وفق نمط محدد، ويستبدل sed النص ويحذفه داخل التدفق دون فتح محرر، ويقسّم awk السطر إلى أعمدة ويستطيع الحساب. فيما يلي أمثلة grep وsed وawk التي تحتاجها فعلاً عند تحليل السجلات وملفات الإعداد ومخرجات الأوامر، مع الأخطاء الشائعة.
متى تستخدم كل أداة
تقرأ الأدوات الثلاث النص سطراً بسطر وتكتب النتيجة إلى المخرج القياسي، لذلك يسهل وصلها ببعضها عبر |. والفرق بينها في المهمة التي تحلّها كل أداة بأفضل شكل.
| المهمة | الأداة | مثال |
|---|---|---|
| إيجاد الأسطر التي تحوي نصاً | grep | grep ERROR app.log |
| استبدال نص | sed | sed 's/http:/https:/g' file |
| حذف أسطر أو عرضها حسب رقمها | sed | sed -n '10,20p' file |
| استخراج عمود | awk | awk '{print $1}' access.log |
| حساب مجموع أو متوسط أو تجميع | awk | awk '{s+=$10} END {print s}' |
قاعدة بسيطة: إذا أردت التصفية فقط فاختر grep، وإذا أردت تغيير النص فاختر sed، وإذا كان في النص أعمدة أو تحتاج إلى حساب فاختر awk.
grep: البحث عن الأسطر وفق نمط
أمثلة grep الأساسية
# الأسطر التي تحتوي كلمة error في الملف
grep error /var/log/syslog
# دون مراعاة حالة الأحرف: Error وERROR وerror
grep -i error app.log
# مع أرقام الأسطر
grep -n "Connection refused" app.log
# بحث متكرر في مجلد، مع أسماء الملفات
grep -rn "DB_HOST" /etc/myapp/
# أسماء الملفات التي يوجد فيها تطابق فقط
grep -rl "TODO" src/
# عكس الاختيار: كل شيء ما عدا التعليقات والأسطر الفارغة
grep -v -e '^#' -e '^$' /etc/ssh/sshd_config
# عدّ الأسطر المتطابقة
grep -c " 500 " access.log
يبحث الخيار -w عن الكلمة كاملة: فالأمر grep -w log لن يجد login. ويُلغي الخيار -F التعبيرات النمطية ويبحث عن النص حرفياً، وهو مفيد حين يحتوي النمط على نقاط أو أقواس أو نجوم.
السياق حول السطر المطابق
نادراً ما يُفهم الخطأ في السجل من سطر واحد، فنحتاج إلى stack trace أو الطلب الذي أدى إليه. ولذلك توجد خيارات السياق:
# 3 أسطر بعد التطابق (After)
grep -A 3 "Traceback" app.log
# سطران قبل التطابق (Before)
grep -B 2 "OOM" /var/log/kern.log
# خمسة أسطر من كل جانب (Context)
grep -C 5 "segfault" /var/log/syslog
يفصل grep بين مجموعات التطابقات بسطر --، فيسهل قراءة المخرجات.
grep والتعبيرات النمطية
يفهم grep افتراضياً التعبيرات الأساسية (BRE). ومع الخيار -E تُفعَّل التعبيرات الموسّعة (ERE)، حيث تعمل + و? و| والأقواس دون شرطات مائلة عكسية.
| البنية | المعنى | مثال |
|---|---|---|
^ | بداية السطر | grep '^root' /etc/passwd |
$ | نهاية السطر | grep 'bash$' /etc/passwd |
. | أي حرف | grep 'h.t' |
* | من 0 تكرار فأكثر | grep 'ab*c' |
+ (ERE) | تكرار واحد فأكثر | grep -E '[0-9]+' |
| (ERE) | أو | grep -E 'error|warn' |
[...] | حرف واحد من المجموعة | grep '[Ee]rror' |
# الأسطر التي تحوي أخطاء أو تحذيرات
grep -E "ERROR|WARN" app.log
# عناوين IP فقط من السجل، واحد في كل سطر (-o تطبع التطابق فقط)
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log
grep -P: استخراج قيمة بين أجزاء معروفة
يملك GNU grep الخيار -P الذي يستخدم تعبيرات نمط Perl. ومعه تتوفر \K («انسَ كل ما تطابق قبل هذا الموضع») والنظر إلى الأمام، فيمكن استخراج القيمة وحدها:
$ echo 'user_id=4821 status=ok' | grep -oP 'user_id=\K[0-9]+'
4821
$ grep -oP '"version":\s*"\K[^"]+' package.json
2.4.1
الخيار -P غير متوفر في كل إصدارات grep (مثلاً لا يوجد في BSD grep على macOS)، لذلك في السكريبتات المحمولة الأفضل استخدام sed أو awk.
grep -q في شروط السكريبتات
grep -q لا يطبع شيئاً، ويعيد رمز الخروج فقط: 0 إذا وُجد التطابق و1 إذا لم يوجد. بهذا يمكن كتابة الفحص داخل if مباشرةً:
if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then
echo "تسجيل دخول root معطّل"
fi
هذا أقصر من حفظ المخرجات في متغير والتحقق من فراغه، ويتوقف grep عند أول تطابق.
sed: استبدال النص وحذفه
الاستبدال: الأمر s
الأمر الأساسي في sed هو s/النمط/البديل/الخيارات. وبدون الخيار g يُستبدل أول تطابق فقط في كل سطر.
# عرض النص بعد الاستبدال (الملف لا يتغير)
sed 's/foo/bar/' file.txt
# استبدال كل التكرارات في السطر
sed 's/foo/bar/g' file.txt
# دون مراعاة حالة الأحرف (GNU sed)
sed 's/error/ERROR/gI' app.log
# فاصل آخر إذا كان النص يحتوي على شرطات مائلة
sed 's|/var/www|/srv/www|g' nginx.conf
sed -i: الاستبدال داخل الملف
يكتب الخيار -i النتيجة فوق الملف الأصلي. ولكي لا تفقد النسخة الأصلية، حدّد لاحقة للنسخة الاحتياطية:
# ينشئ config.ini.bak ويعدّل config.ini
sed -i.bak 's/^debug=true/debug=false/' config.ini
# استبدال في كل ملفات .conf داخل المجلد
find /etc/myapp -name "*.conf" -exec sed -i 's/old-host/new-host/g' {} +
قبل أي تعديل جماعي شغّل الأمر أولاً دون -i وراقب المخرجات. وفي macOS (BSD sed) يكون للخيار -i معامل إجباري: sed -i '' 's/a/b/' file.
العمل على الأسطر بحسب رقمها أو نمطها
# عرض الأسطر من 10 إلى 20 (-n يلغي الطباعة التلقائية، وp للطباعة)
sed -n '10,20p' file.txt
# حذف السطر 5
sed '5d' file.txt
# حذف السطر الأخير
sed '$d' file.txt
# حذف الأسطر الفارغة والتعليقات
sed -e '/^$/d' -e '/^#/d' nginx.conf
# الاستبدال في الأسطر التي تحوي "listen" فقط
sed '/listen/s/80/8080/' nginx.conf
# إدراج سطر بعد التطابق (GNU sed)
sed '/^\[mysqld\]/a max_connections = 500' my.cnf
المراجع الخلفية و&
يمكن إعادة الجزء المحصور بين الأقواس في النمط داخل البديل عبر \1 و\2، والرمز & يعني النص المتطابق كله.
# تبديل الاسم واللقب (ERE عبر -E)
$ echo "Ahmed Ali" | sed -E 's/(\S+) (\S+)/\2 \1/'
Ali Ahmed
# وضع كل الأرقام بين أقواس مربعة
$ echo "port 8080, timeout 30" | sed -E 's/[0-9]+/[&]/g'
port [8080], timeout [30]
# تحويل التاريخ 2026-10-14 إلى 14.10.2026
$ echo 2026-10-14 | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/'
14.10.2026
awk: الأعمدة والشروط والحسابات
طباعة العمود المطلوب
يقسّم awk كل سطر إلى حقول حسب المسافات والتبويبات: $1 هو الحقل الأول، و$2 الثاني، و$NF الأخير، و$0 السطر كله.
# عناوين IP من سجل nginx (العمود الأول)
awk '{print $1}' /var/log/nginx/access.log
# اسم المستخدم وshell من /etc/passwd (الفاصل النقطتان)
awk -F: '{print $1, $7}' /etc/passwd
# العمود الأخير
df -h | awk '{print $NF}'
# فاصل مخرجات مخصص
awk -F: -v OFS=';' '{print $1, $3}' /etc/passwd
الشروط: طباعة الأسطر المطلوبة فقط
يمكن وضع شرط قبل الكتلة بين الأقواس المجعّدة، فينفّذ awk الإجراء للأسطر المناسبة فقط.
# المستخدمون ذوو UID من 1000 فما فوق (العاديون، لا النظاميون)
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
# الطلبات برمز استجابة 500 فأكثر (الحقل التاسع في صيغة combined)
awk '$9 >= 500' access.log
# الأسطر التي يطابق فيها العمود السادس تعبيراً نمطياً
awk '$6 ~ /POST/' access.log
# الملفات الأكبر من 100 ميغابايت من مخرجات ls -l
ls -l | awk '$5 > 100*1024*1024 {print $9}'
BEGIN وEND وNR: awk كبرنامج صغير
تُنفَّذ الكتلة BEGIN قبل قراءة السطر الأول، وEND بعد السطر الأخير. ويحفظ NR رقم السطر الحالي، وفي كتلة END يحمل عدد الأسطر كلها.
# مجموع أحجام الردود (الحقل العاشر) بالميغابايت
awk '{sum += $10} END {printf "%.1f MB\n", sum/1024/1024}' access.log
# متوسط زمن الاستجابة من العمود الأخير
awk '{s += $NF} END {if (NR) print s/NR}' timings.log
# تخطي سطر العناوين في ملف CSV
awk -F, 'NR > 1 {print $2}' users.csv
# عدّ الطلبات لكل IP: مصفوفة ترابطية
awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access.log | sort -rn | head
المثال الأخير من الكلاسيكيات في تحليل السجلات: تحل المصفوفة count ذات المفتاح IP محل الثنائي sort | uniq -c، ويسهل توسيعها، مثلاً لحساب حجم الحركة لكل عنوان.
خطوط الأنابيب: grep وsed وawk معاً
تكمن القوة الحقيقية في الجمع بينها. تؤدي كل أداة جزءها، ويمرر | النتيجة إلى التالية.
أعلى 10 عناوين IP تولّد أخطاء 5xx
grep ' 50[0-9] ' /var/log/nginx/access.log \
| awk '{print $1}' \
| sort | uniq -c | sort -rn | head -10
412 203.0.113.45
118 198.51.100.7
36 192.0.2.19
هنا يختار grep الأسطر بشكل تقريبي، ويستخرج awk الحقل، ويعدّ sort | uniq -c التكرارات. ويمكن كتابة الأمر كله في awk واحد: awk '$9 ~ /^5/ {c[$1]++} END {for (i in c) print c[i], i}' access.log | sort -rn | head، وهذه النسخة أدق لأنها تتحقق من عمود رمز الاستجابة نفسه.
أكثر عناوين URL زيارةً
awk '{print $7}' access.log | sed 's/?.*//' | sort | uniq -c | sort -rn | head
يقطع sed هنا سلسلة الاستعلام، حتى تُحسب /search?q=a و/search?q=b صفحة واحدة.
قيم الإعدادات دون التعليقات
grep -v '^\s*#' /etc/myapp/app.env | grep '=' | awk -F= '{print $1}'
الأخطاء في ساعة محددة
grep '14/Oct/2026:03:' access.log | awk '$9 >= 500 {print $4, $7, $9}'
الأخطاء الشائعة
- استخدام علامات الاقتباس المزدوجة بدلاً من المفردة في awk. في
awk "{print $1}"يستبدل الصدفة$1بمتغيرها الخاص قبل تشغيل awk. اكتب برنامج awk وتعبيرات sed بين علامتي اقتباس مفردتين. - نسيان
gفي sed. بدونها يُستبدل أول تطابق فقط في السطر، وتبقى البقية كما هي. sed -iدون تحقق. التعبير النمطي الخاطئ يفسد الملف بصمت. شغّل الأمر أولاً دون-i، أو استخدم-i.bak.+و|لا تعملان في grep. هذه صيغة موسّعة، وتحتاج إلىgrep -E(أوsed -E).- النقطة في النمط. الأمر
grep 192.168.1.1سيجد أيضاً192x168y1z1، لأن النقطة تعني «أي حرف». استخدمgrep -Fأو اكتب\.. - المسافات في الأعمدة. إذا كان الحقل قد يحتوي على مسافات (CSV أو مسار)، فحدّد الفاصل صراحةً:
awk -F,أوawk -F'\t'. - استخدام cat دون حاجة.
cat file | grep xيعمل، لكنgrep x fileأقصر ولا ينشئ عملية إضافية.
بدائل grep وsed وawk
هذه الأدوات غير ملائمة لملفات JSON: يُفضَّل تحليل البنية بـ jq (jq '.items[] | select(.status=="active") | .name')، وملفات YAML بـ yq. وللبحث التكراري السريع في المشاريع الكبيرة يُستخدم كثيراً ripgrep (الأمر rg)، الذي يأخذ .gitignore في الحسبان افتراضياً. ولمن يفضّل صياغة Perl، فإن perl -pe 's/a/b/g' وperl -lane 'print $F[0]' تغنيان عن sed وawk في سطر واحد. لكن grep وsed وawk متوفرة تقريباً على أي خادم دون تثبيت، لذلك تستحق التعلّم أولاً.
الخلاصة
يبحث grep عن الأسطر، ويعدّلها sed، ويعمل awk على الأعمدة ويحسب. احفظ المجموعة الأساسية: grep -rniE و-A/-B/-C، وsed 's/.../.../g' مع -i.bak و-n 'Np'، وawk -F مع $1 و$NF والشروط وكتلة END. ومن هذه اللبنات يُبنى تقريباً أي تحليل للسجلات. وقد جرى شرح هذه الأمثلة عملياً مع find وjq وcurl في درس Linux عن معالجة النصوص في الطرفية.
الأسئلة الشائعة
ما الفرق بين grep وegrep؟
egrep اسم مستعار قديم لـ grep -E (التعبيرات النمطية الموسّعة). الإصدارات الحديثة من GNU grep تطبع تحذيراً عند استدعاء egrep، لذلك اكتب grep -E.
كيف أبحث عن نص في كل ملفات مجلد في Linux؟
استخدم grep -rn "النص" /المسار: الخيار -r للبحث المتكرر، والخيار -n لعرض رقم السطر. ولتحديد أنواع الملفات أضف --include="*.php".
كيف أستبدل نصاً في ملفات كثيرة دفعة واحدة؟
اجمع البحث مع sed: grep -rl "old" . | xargs sed -i 's/old/new/g'. وقبل ذلك يُفضَّل عمل commit أو نسخة احتياطية.
كيف أطبع عدة أعمدة في awk مفصولة بتبويب؟
حدّد فاصل المخرجات: awk -v OFS='\t' '{print $1, $3}' file. وبدون OFS تُفصل الحقول بمسافة.
كيف أحذف المسافات في نهاية الأسطر باستخدام sed؟
الأمر sed -i 's/[[:space:]]*$//' file يحذف المسافات والتبويبات في نهاية كل سطر في الملف.
يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Linux: с нуля до уверенного администрирования».
الانتقال إلى الدورة