grep در لینوکس: جستوجوی متن در فایل و لوله
کار با grep، ERE، بازگشتی، -n، -r، ripgrep و اشتباههای رایج جستوجوی لاگ و کد در لینوکس.
Founder & product engineer

وقتی خطای production فقط در یک سرویس از ده سرویس ظاهر میشود، اولین حرکت اغلب این نیست که کل فایل را در ادیتور باز کنید؛ بلکه میپرسید: کجا این رشته آمده؟ grep ابزار کلاسیک فیلتر کردن خطوطی است که با یک الگو میخوانند — روی فایل، روی درخت پروژه، یا روی خروجی فرمان قبلی در لوله.
قدرت grep در سادگی قرارداد است: ورودی خطبهخط، خروجی خطوط مطابق. ضعفش وقتی است که الگو را اشتباه بنویسید، encoding را نادیده بگیرید، یا روی باینری و درخت عظیم بدون فیلتر بزنید و ترمینال را قفل کنید.

پاسخ کوتاه
برای یافتن یک رشتهٔ ثابت: `grep -n 'error' app.log`. برای نادیده گرفتن حروف بزرگ/کوچک: `-i`. برای بازگشتی در پوشه با نام فایل: `grep -rn 'TODO' src/`. برای الگوی گستردهتر از ثابت ساده، ERE با `-E` یا `grep -E`. خروجی را میتوانید به لوله بدهید؛ خود grep هم اغلب آخر لوله است. برای کدبیس بزرگ امروزی، ripgrep (`rg`) جایگزین سریعتری است؛ ولی grep همهجا هست و زبان مشترک سرورهاست.
grep سوال «کدام خط؟» را جواب میدهد؛ سوال «چرا؟» را باید با زمینهٔ اطراف خط و دانش سیستم بسازید.
شکل پایه و خواندن خروجی
bash
grep 'timeout' /var/log/app/app.log grep -n 'timeout' /var/log/app/app.log grep -n --color=auto 'timeout' /var/log/app/app.log
-n شمارهٔ خط را میآورد — برای پرش در ادیتور حیاتی است. رنگ فقط برای انسان مفید است؛ در اسکریپت و لوله معمولاً خاموشش کنید یا به --color=never تکیه کنید تا کد ANSI قاطی داده نشود.
ثابت در برابر عبارت منظم
بهصورت پیشفرض grep از Basic Regular Expressions استفاده میکند؛ برای خیلی از کارها کافی است ولی پرانتز و + رفتار غیرشهودی دارند. دو مسیر امن:
- رشتهٔ تحتاللفظی: grep -F یا fgrepگونهها — متاکاراکتر را خاص نمیداند.
- ERE خوانا: grep -E 'err(or|ors)' یا معادل.
bash
grep -F 'status=500' app.log grep -E 'status=(500|502|503)' app.log grep -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}' app.log
اگر دنبال متنی میگردید که خودش نقطه یا ستاره دارد، -F جلوی سورپرایز را میگیرد.
چند فایل و بازگشتی
bash
grep -n 'TODO' src/*.py grep -rn 'TODO' src/ grep -rn --include='*.py' 'TODO' src/ grep -rn --exclude-dir='.git' --exclude-dir='node_modules' 'password' .
بدون --exclude-dir روی ریپوهای جاوااسکریپت، بیشتر وقت را در node_modules تلف میکنید. برای اسرار، جستوجوی خام جای اسکنر تخصصی را نمیگیرد ولی برای نشت اتفاقی در کد خودتان سریع است.
معکوس، تعداد، و فقط نام فایل
bash
grep -v 'DEBUG' app.log | head grep -c 'ERROR' app.log grep -l 'deprecated' src/**/*.py grep -L 'license' src/*.py
-v خطوط غیرمطابق، -c شمارش، -l فقط فایلهای دارای تطبیق، -L فایلهای بدون تطبیق. اینها برای گزارش و اسکریپت از چاپ هزاران خط مفیدترند.
زمینهٔ اطراف تطبیق
bash
grep -n -A2 -B2 'NullPointer' app.log grep -n -C3 'NullPointer' app.log
در لاگ، خود خط خطا اغلب کافی نیست؛ دو خط قبل stack یا request id را نشان میدهد. -C فشردهٔ -A/-B است.
لوله: grep بهعنوان فیلتر
bash
ps aux | grep '[n]ginx' journalctl -u nginx -n 200 --no-pager | grep -i error ss -tlnp | grep ':443'
ترفند [n]ginx جلوی خود خط grep را در خروجی ps میگیرد. ترکیب با journalctl و ss در عیبیابی سرور روزمره است.
Binary، encoding و فایلهای عجیب
bash
grep -a 'string' binary.dat grep -I -rn 'secret' . file app.log | head
grep روی باینری ممکن است بگوید Binary file matches. -a باینری را مثل متن میخواند؛ -I باینری را رد میکند. لاگ UTF-8 شکسته یا UTF-16 گاهی تطبیق را از دست میدهد — اول file و encoding را بفهمید.
کارایی روی فایل بزرگ
روی فایل چندگیگابایتی، ابتدا با tail/journal فیلتر زمانی بدهید، بعد grep. جستوجوی بازگشتی روی کل دیسک بدون مسیر هدف، هم کند است هم خطر خواندن فایلهای نامربوط دارد.
bash
tail -n 5000 /var/log/app/app.log | grep -n 'timeout' grep -n 'timeout' /var/log/app/app.log | tail -n 20
ترتیب فرق دارد: اول tail یعنی فقط انتهای فایل؛ اول grep یعنی همهٔ تطبیقها سپس ته لیست.
مقایسه با ابزارهای نزدیک
| نیاز | ابزار |
|---|---|
| خط مطابق الگو | grep / rg |
| جایگزینی متن در جریان | sed |
| پردازش ستونی/فیلدی | awk |
| یافتن فایل بر اساس نام/متا | find |
| جستوجوی کد سریع با ignore | ripgrep (rg) |
grep جایگزین sed برای ویرایش نیست؛ فقط فیلتر است. برای پیدا کردن فایل با نام `*.conf` از find استفاده کنید نه grep.
ripgrep در کنار grep
bash
command -v rg && rg -n 'TODO' src rg -n -g '*.py' 'TODO' src rg -n --hidden -g '!.git' 'API_KEY' .
rg بهطور پیشفرض بسیاری پوشههای نویزی را نادیده میگیرد و سریعتر است. روی سرور قفلشده ممکن است نصب نباشد؛ پس هنوز grep را بلد باشید. در مستند تیم بگویید کدام استاندارد است.
اشتباههای رایج
- فراموش کوتیشن دور الگو و انبساط شل روی * و ؟.
- grep روی مسیر بدون exclude و گیر کردن در .git یا vendor.
- تفسیر نادرست Bre در برابر نیاز به -F یا -E.
- اتکا به رنگ در خروجی اسکریپت.
- جستوجوی رمز عبور در لاگ بدون کنترل دسترسی به همان لاگ.
الگوی عملی عیبیابی
- بازهٔ زمانی لاگ را تنگ کنید (journalctl --since یا فایل چرخششدهٔ درست).
- یک request id یا کد خطا را با grep -n پیدا کنید.
- با -C زمینه را ببینید.
- اگر چند سرویس است، همین الگو را روی بقیه تکرار و زمانها را همتراز کنید.
این زنجیره از «grep error روی همه چیز» مؤثرتر است چون نویز DEBUG را کم میکند.
grep در اسکریپت و کد خروج
bash
if grep -q 'READY' /tmp/status; then echo ok; else echo missing; exit 1; fi grep -R -n --include='*.env' -E '^(PASSWORD|SECRET)=' . && echo 'review these' || true
-q سکوت میکند و فقط کد خروج میدهد: ۰ یعنی حداقل یک تطبیق. در CI برای «نباید این الگو باشد» از معکوس منطقی استفاده کنید.
چند الگو همزمان
bash
grep -E 'ERROR|FATAL|PANIC' app.log grep -e ERROR -e FATAL app.log grep -f patterns.txt app.log
فایل الگو برای لیست بلند بهتر است؛ نسخه را در ریپو نگه دارید تا تیم یکسان بجوید.
محدودیتها
grep موتور جستوجوی معنایی کد نیست؛ refactor و ارجاع نماد را از IDE یا ابزار زبان بخواهید. برای JSON تودرتو، گاهی jq دقیقتر از regex روی کل خط است. برای متن چندخطی، الگوهای خطمحور محدودیت دارند و باید به ابزارهای دیگر یا حالتهای خاص فکر کنید.
الگوهای امن برای اسرار در درخت کد
جستوجوی `API_KEY` یا `BEGIN PRIVATE KEY` با grep شروع خوبی برای بهداشت ریپو است، اما جای اسکنر اختصاصی و هوک pre-commit را نمیگیرد. نتیجه را در تیکت امنیتی با دسترسی محدود نگه دارید نه در کانال عمومی.
bash
grep -R -n --exclude-dir=.git --exclude-dir=node_modules -E 'BEGIN (RSA |OPENSSH )?PRIVATE KEY' . || true
اگر چیزی پیدا شد، چرخش اعتبارنامه را جدیتر از پاک کردن خط از تاریخ git ببینید — تاریخچه ممکن است هنوز کپی داشته باشد.
grep و پروندههای لاگ چرخششده
روی سیستمهایی با logrotate، فایل فعلی فقط بخشی از داستان است. `app.log.1` و فشردهها را در دامنه بگذارید یا از journal استفاده کنید. جستوجوی ناقص باعث نتیجهگیری غلط «خطا نبود» میشود.
bash
zgrep -n 'timeout' /var/log/app/app.log.*.gz 2>/dev/null | tail grep -n 'timeout' /var/log/app/app.log /var/log/app/app.log.1 2>/dev/null | tail
خوانایی الگو برای تیم
الگوی پیچیده را در فایل و با توضیح بالای آن نگه دارید. یکخطیهای رمزآلود در چت زود فراموش میشوند. اگر الگو بیش از یک خط توضیح نیاز دارد، شاید ابزار ساختیافتهتر (jq روی JSON) مناسبتر باشد.
حداقلهای regex که واقعاً لازم دارید
برای کار روزانه اغلب همینها کافیاند: `.` یک نویسه، `*` تکرار، `^` و `$` ابتدا/انتهای خط، کلاسهایی مثل `[0-9]`, و با `-E` عملگر `|` برای یا. بهجای حفظ همهٔ گوشهها، یک برگهٔ تقلب تیمی و تست روی نمونه نگه دارید.
bash
grep -E '^(ERROR|FATAL)\b' app.log | head grep -E 'request_id=[a-f0-9-]{36}' app.log | head
وقتی الگو از ۱۰–۱۵ نویسهٔ خاص پیچیدهتر شد، احتمال خطا بالا میرود؛ همانجا به ابزار ساختیافته فکر کنید. regex روی متن آزاد همیشه بدهی فنی پنهان دارد.
در code review، الگوی grep داخل اسکریپت CI را مثل کد واقعی ببینید: نامگذاری، توضیح، و نمونهٔ ورودی/خروجی داشته باشد.
خلاصه
grep فیلتر خطمحور همهجایی لینوکس است: -n برای مکان، -F/-E برای نوع الگو، -r با exclude برای درخت، و لوله برای ترکیب با ps و journal. روی کدبیس بزرگ rg را بشناسید؛ روی سرور مینیمال grep کافی است. الگو را کوتیشن کنید و قبل از جستوجوی وسیع، دامنه را تنگ کنید.
سوالات متداول
تفاوت egrep و grep -E چیست؟
egrep از نظر تاریخی ERE را پیشفرض میکند؛ امروزه معمولاً grep -E توصیهشده و قابلحملتر در مستندهای جدید است.
چطور فقط تطبیق را چاپ کنم نه کل خط؟
از -o استفاده کنید: `grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' app.log` برای استخراج IPگونه.
چرا چیزی پیدا نمیشود ولی در ادیتور هست؟
مسیر اشتباه، exclude پنهان، CRLF، یا الگوی Bre. با -F رشتهٔ ثابت و مسیر مطلق را بیازمایید.
منابع و مراجع
- GNU Grep Manual: https://www.gnu.org/software/grep/manual/grep.html
- grep(1) — Linux manual page: https://man7.org/linux/man-pages/man1/grep.1.html
- POSIX grep: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html
- ripgrep User Guide: https://github.com/BurntSushi/ripgrep/blob/master/GUIDE.md
Author
Soheil Ebrahimpour is the founder of FutureForge. He works on product design, architecture, and getting custom software into production.
Related notes
If you are unsure about architecture or the build path, we can talk about the project.
Describe the problem and the constraints. If there is a fit, we will schedule a conversation.




