رفتن به محتوا
LoopX

جستجو با grep و regex

توی این درس یاد می‌گیری با grep در فایل‌ها و خروجی دستورها دنبال هر متنی بگردی. flag های مهم را می‌شناسی: -i (بی‌حساس به حروف)، -n (شماره‌ی خط)، -v (خط‌هایی که ندارند)، -c (شمارش)، -r (همه‌ی فایل‌های یک پوشه)، -E (regex توسعه‌یافته)، -o (فقط بخش منطبق) و -w (کلمه‌ی کامل). regex را از پایه یاد می‌گیری: . و * و ^ و $ و [ ] و بعد + و ? و | و { }. تمرین: همه‌ی خط‌های ERROR را در لاگ‌های یک پوشه با شماره‌ی خط پیدا می‌کنی.

مسئله: سوزن در انبار کاه

Section titled “مسئله: سوزن در انبار کاه”

لاگ ۵۰۰ هزار خطی داری و دنبال «فقط خطاها»، «فقط یک IP»، «همه‌ی ایمیل‌ها» یا «خط‌هایی که با تاریخ امروز شروع می‌شوند» هستی. با چشم نمی‌شود؛ با grep (که نامش از دستور قدیمی «global regular expression print» است) در چند میلی‌ثانیه جواب می‌گیری. و چون grep از خروجی دستورها هم می‌خواند، تقریباً در هر pipeline حضور دارد.

تشبیه: Ctrl+F بسیار قدرتمند

Section titled “تشبیه: Ctrl+F بسیار قدرتمند”

grep مثل Ctrl+F است، ولی روی میلیون‌ها خط، با الگو (نه فقط متن ثابت)، روی چندین فایل و قابل استفاده در دستورها. و regex زبانی است که با آن الگو می‌نویسی: به‌جای «دقیقاً این کلمه»، می‌گویی «سه رقم، یک نقطه، سه رقم…» (یک آدرس IP).

grep هر خط را با الگو مقایسه می‌کند و خط‌های منطبق را (یا با -v خط‌های غیرمنطبق) چاپ می‌کند. ورودی می‌تواند فایل، چند فایل، یا stdin (pipe) باشد.

یک پوشه‌ی لاگ نمونه می‌سازیم (چند فایل، با انواع خط):

Terminal window
mkdir -p logs/archive
cat > logs/app.log <<'LXEOF'
2026-10-03 09:00:01 INFO server started on port 8080
2026-10-03 09:00:05 INFO user ali@example.com logged in from 203.0.113.5
2026-10-03 09:01:10 WARN disk usage at 85%
2026-10-03 09:02:33 ERROR database connection failed: timeout
2026-10-03 09:02:34 ERROR retry 1 failed for 198.51.100.7
2026-10-03 09:03:00 INFO user sara@example.org logged in from 192.0.2.44
2026-10-03 09:03:42 error invalid token for user ali
2026-10-03 09:04:15 INFO request done in 120ms
2026-10-03 09:05:00 DEBUG cache hit ratio 0.93
2026-10-03 09:05:01 ERROR_CODE=500 returned for /api/orders
2026-10-03 09:06:12 INFO backup completed
LXEOF
cat > logs/error.log <<'LXEOF'
2026-10-03 10:15:02 ERROR out of memory
2026-10-03 10:15:09 INFO service restarted
2026-10-03 10:16:00 ERROR disk full on /var
LXEOF
echo "no problems here" > logs/archive/old.log
printf 'binary-ish\0data ERROR inside\n' > logs/archive/data.bin
ls -R logs
خروجی
logs:
app.log
archive
error.log
logs/archive:
data.bin
old.log

grep الگو فایل: هر خطی که الگو را دارد چاپ می‌شود:

Terminal window
grep ERROR logs/app.log
خروجی
2026-10-03 09:02:33 ERROR database connection failed: timeout
2026-10-03 09:02:34 ERROR retry 1 failed for 198.51.100.7
2026-10-03 09:05:01 ERROR_CODE=500 returned for /api/orders

سه خط: ERROR database...، ERROR retry... و ERROR_CODE=500... (چون ERROR بخشی از ERROR_CODE است). حالا flag های اصلی:

Terminal window
echo "--- -n (شماره‌ی خط):"
grep -n ERROR logs/app.log
echo "--- -c (فقط تعداد خط‌های منطبق):"
grep -c ERROR logs/app.log
echo "--- -i (بی‌حساس به حروف؛ error و ERROR هر دو):"
grep -i -c error logs/app.log
echo "--- -v (خط‌هایی که ERROR ندارند؛ تعداد):"
grep -v -c ERROR logs/app.log
echo "--- -w (کلمه‌ی کامل؛ ERROR_CODE حذف می‌شود):"
grep -w ERROR logs/app.log
خروجی
--- -n (شماره‌ی خط):
4:2026-10-03 09:02:33 ERROR database connection failed: timeout
5:2026-10-03 09:02:34 ERROR retry 1 failed for 198.51.100.7
10:2026-10-03 09:05:01 ERROR_CODE=500 returned for /api/orders
--- -c (فقط تعداد خط‌های منطبق):
3
--- -i (بی‌حساس به حروف؛ error و ERROR هر دو):
4
--- -v (خط‌هایی که ERROR ندارند؛ تعداد):
9
--- -w (کلمه‌ی کامل؛ ERROR_CODE حذف می‌شود):
2026-10-03 09:02:33 ERROR database connection failed: timeout
2026-10-03 09:02:34 ERROR retry 1 failed for 198.51.100.7

-i علاوه بر ۳ خط قبلی، خط error invalid token را هم گرفت. -v «وارونه» است. -w فقط وقتی تطبیق می‌دهد که الگو یک کلمه‌ی کامل باشد (حرف/عدد/خط‌زیر اطراف نداشته باشد)؛ پس ERROR_CODE خارج شد.

مثال ۲: فقط بخش منطبق و مشاهده‌ی context

Section titled “مثال ۲: فقط بخش منطبق و مشاهده‌ی context”

-o فقط خودِ بخش منطبق را چاپ می‌کند (نه کل خط)، که برای استخراج داده عالی است:

Terminal window
echo "--- -o: فقط کلمه‌ی منطبق + شماره‌ی خط:"
grep -on "ERROR" logs/app.log | head -3
echo "--- context: ۱ خط قبل و ۱ بعد از اولین ERROR (-m 1 -B1 -A1):"
grep -m 1 -B1 -A1 ERROR logs/app.log
خروجی
--- -o: فقط کلمه‌ی منطبق + شماره‌ی خط:
4:ERROR
5:ERROR
10:ERROR
--- context: ۱ خط قبل و ۱ بعد از اولین ERROR (-m 1 -B1 -A1):
2026-10-03 09:01:10 WARN disk usage at 85%
2026-10-03 09:02:33 ERROR database connection failed: timeout
2026-10-03 09:02:34 ERROR retry 1 failed for 198.51.100.7

-A N (after) N خط بعد، -B N (before) N خط قبل و -C N هر دو را نشان می‌دهد. -m N بعد از N تطبیق می‌ایستد. این‌ها برای فهمیدن «قبل و بعد از خطا چه شد» حیاتی‌اند.

مثال ۳: جستجو در چند فایل و پوشه

Section titled “مثال ۳: جستجو در چند فایل و پوشه”
Terminal window
echo "--- چند فایل (نام فایل خودکار نمایش داده می‌شود):"
grep ERROR logs/app.log logs/error.log | cut -c1-60
echo "--- -r (بازگشتی در پوشه؛ -n شماره‌ی خط):"
grep -rn ERROR logs
echo "--- -l (فقط اسم فایل‌هایی که دارند):"
grep -rl ERROR logs
echo "--- --include برای محدود کردن به نوع فایل:"
grep -rn --include="*.log" "ERROR" logs | cut -c1-50 | head -3
خروجی
--- چند فایل (نام فایل خودکار نمایش داده می‌شود):
logs/app.log:2026-10-03 09:02:33 ERROR database connection f
logs/app.log:2026-10-03 09:02:34 ERROR retry 1 failed for 19
logs/app.log:2026-10-03 09:05:01 ERROR_CODE=500 returned for
logs/error.log:2026-10-03 10:15:02 ERROR out of memory
logs/error.log:2026-10-03 10:16:00 ERROR disk full on /var
--- -r (بازگشتی در پوشه؛ -n شماره‌ی خط):
logs/error.log:1:2026-10-03 10:15:02 ERROR out of memory
logs/error.log:3:2026-10-03 10:16:00 ERROR disk full on /var
logs/app.log:4:2026-10-03 09:02:33 ERROR database connection failed: timeout
logs/app.log:5:2026-10-03 09:02:34 ERROR retry 1 failed for 198.51.100.7
logs/app.log:10:2026-10-03 09:05:01 ERROR_CODE=500 returned for /api/orders
grep: logs/archive/data.bin: binary file matches
--- -l (فقط اسم فایل‌هایی که دارند):
logs/error.log
logs/archive/data.bin
logs/app.log
--- --include برای محدود کردن به نوع فایل:
logs/error.log:1:2026-10-03 10:15:02 ERROR out of
logs/error.log:3:2026-10-03 10:16:00 ERROR disk fu
logs/app.log:4:2026-10-03 09:02:33 ERROR database

این همان تمرین درس است: grep -rn "ERROR" logs/ همه‌ی خط‌های ERROR را در همه‌ی فایل‌های پوشه با شماره‌ی خط می‌دهد. فایل data.bin هم یک خط ERROR داشت ولی چون باینری است (حاوی بایت NUL)، به‌جای چاپ خط فقط می‌گوید «Binary file matches»؛ در مثال بعد می‌بینی.

⚡ بررسی سریع

grep -rn ERROR logs چه می‌کند؟

مثال ۴: regex پایه، اولین عناصر

Section titled “مثال ۴: regex پایه، اولین عناصر”

بدون flag، grep از regex پایه (BRE) استفاده می‌کند. نمادهای مهم:

نماد معنی
. هر یک کاراکتر
* صفر یا چند بار تکرار کاراکتر قبلی
^ ابتدای خط
$ انتهای خط
[abc] یکی از a، b، c
[a-z]، [0-9] بازه
[^abc] هر کاراکتر به‌جز این‌ها
\. خودِ نقطه (escape)
Terminal window
echo "--- خط‌هایی که با 2026-10-03 09:00 شروع می‌شوند (^):"
grep -c '^2026-10-03 09:00' logs/app.log
echo "--- خط‌هایی که به done ختم می‌شوند (\$):"
grep 'done$' logs/app.log
echo "--- خط‌های خالی (^\$) با شماره:"
grep -n '^$' logs/app.log
echo "--- E.ROR (نقطه = هر یک کاراکتر):"
grep -c 'E.ROR' logs/app.log
echo "--- ERR*OR (* = تکرار R قبلی؛ صفر یا بیشتر):"
grep -c 'ERR*OR' logs/app.log
echo "--- INFO یا WARN با [IW]:"
grep -c '[IW][NA][FR]' logs/app.log
خروجی
--- خط‌هایی که با 2026-10-03 09:00 شروع می‌شوند (^):
2
--- خط‌هایی که به done ختم می‌شوند ($):
--- خط‌های خالی (^$) با شماره:
11:
--- E.ROR (نقطه = هر یک کاراکتر):
3
--- ERR*OR (* = تکرار R قبلی؛ صفر یا بیشتر):
3
--- INFO یا WARN با [IW]:
6

ترکیب ^$ یعنی «ابتدا و بلافاصله انتها» = خط خالی. نقطه (.) در regex هر کاراکتر است، نه فقط نقطه؛ برای نقطه‌ی واقعی \. بنویس.

مثال ۵: regex توسعه‌یافته، -E

Section titled “مثال ۵: regex توسعه‌یافته، -E”

با -E (یا دستور egrep) نمادهای قوی‌تری داری که بدون بک‌اسلش کار می‌کنند:

نماد معنی
+ یک یا چند بار
? صفر یا یک بار
| «یا»
( ) گروه‌بندی
{n} / {n,m} دقیقاً n بار / n تا m بار
Terminal window
echo "--- ERROR یا WARN:"
grep -E 'ERROR|WARN' logs/app.log | cut -c1-40
echo "--- آدرس IP (چهار گروه عدد):"
grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' logs/app.log
echo "--- ایمیل‌ها:"
grep -oE '[a-z]+@[a-z]+\.[a-z]+' logs/app.log
echo "--- مدت زمان به میلی‌ثانیه:"
grep -oE '[0-9]+ms' logs/app.log
echo "--- درصد (۱ یا ۲ رقم + %):"
grep -oE '[0-9]{1,2}%' logs/app.log
خروجی
--- ERROR یا WARN:
2026-10-03 09:01:10 WARN disk usage at
2026-10-03 09:02:33 ERROR database conne
2026-10-03 09:02:34 ERROR retry 1 failed
2026-10-03 09:05:01 ERROR_CODE=500 retur
--- آدرس IP (چهار گروه عدد):
203.0.113.5
198.51.100.7
192.0.2.44
--- ایمیل‌ها:
ali@example.com
sara@example.org
--- مدت زمان به میلی‌ثانیه:
120ms
--- درصد (۱ یا ۲ رقم + %):
85%

-o با -E ترکیب بسیار قدرتمندی است: استخراج الگوها (IP، ایمیل، عدد) از متن. در regex بالا [0-9]{1,3}(\.[0-9]{1,3}){3} یعنی «۱ تا ۳ رقم، و بعد سه بار (نقطه + ۱ تا ۳ رقم)» = IP. بدون -E در BRE باید \+، \?، \|، \(، \{ بنویسی؛ -E ساده‌تر است.

مثال ۶: کلاس‌های کاراکتری POSIX و \b

Section titled “مثال ۶: کلاس‌های کاراکتری POSIX و \b”

برای خوانایی و سازگاری با زبان/محلی، نام‌دار هم هست:

Terminal window
echo "--- [[:digit:]] یعنی [0-9] ؛ خط‌هایی با یک عدد 3 رقمی کنار هم:"
grep -E '[[:digit:]]{3}' logs/app.log | cut -c1-45 | head -3
echo "--- [[:upper:]]{4,} یعنی ۴ حرف بزرگ یا بیشتر:"
grep -oE '[[:upper:]]{4,}' logs/app.log | sort | uniq -c
echo "--- \\bERROR\\b (مرز کلمه) مثل -w:"
grep -c '\bERROR\b' logs/app.log
خروجی
--- [[:digit:]] یعنی [0-9] ؛ خط‌هایی با یک عدد 3 رقمی کنار هم:
2026-10-03 09:00:01 INFO server started on p
2026-10-03 09:00:05 INFO user ali@example.co
2026-10-03 09:01:10 WARN disk usage at 85%
--- [[:upper:]]{4,} یعنی ۴ حرف بزرگ یا بیشتر:
1 CODE
1 DEBUG
3 ERROR
5 INFO
1 WARN
--- \bERROR\b (مرز کلمه) مثل -w:
2

کلاس‌های رایج: [[:digit:]]، [[:alpha:]]، [[:alnum:]]، [[:upper:]]، [[:lower:]]، [[:space:]]، [[:punct:]]. \b در GNU grep «مرز کلمه» است. اگر regex مدرن‌تر (\d، \w، (?i)) می‌خواهی، grep -P (Perl regex) را امتحان کن (روی GNU grep موجود است).

مثال ۷: متن ثابت، -F، و رفتار کاراکترهای خاص

Section titled “مثال ۷: متن ثابت، -F، و رفتار کاراکترهای خاص”

اگر الگوی تو کاراکتر خاص دارد (مثل .، *، [، $)، یا باید escape کنی یا -F (fixed string: «الگو را متن عادی بگیر») بدهی:

Terminal window
printf 'version 1.5\nversion 125\nprice $5.00\n' > v.txt
echo "--- grep 1.5 (نقطه = هر کاراکتر):"
grep '1.5' v.txt
echo "--- grep -F 1.5 (نقطه عادی):"
grep -F '1.5' v.txt
echo "--- گرفتن علامت دلار:"
grep -F '$5' v.txt
خروجی
--- grep 1.5 (نقطه = هر کاراکتر):
version 1.5
version 125
--- grep -F 1.5 (نقطه عادی):
version 1.5
--- گرفتن علامت دلار:
price $5.00

1.5 در regex با 125 هم جور شد چون . هر کاراکتر است. -F همه‌ی نمادها را عادی می‌بیند و سریع‌تر هم است (برای جستجوی متن‌های ثابت و حاوی علامت). و برای فهرستی از الگوها: grep -f patterns.txt فایل.

grep اغلب ورودی را از دستور دیگر می‌گیرد:

Terminal window
echo "--- نام پروسه‌هایی که bash هستند (یکتا):"
ps -eo comm | grep -w bash | sort -u
echo "--- کاربرهای دارای shell واقعی در /etc/passwd:"
grep -v 'nologin\|false' /etc/passwd | cut -d: -f1,7
echo "--- ۳ پرتکرارترین کلمه‌ی ERROR/WARN/INFO در لاگ:"
grep -oE 'ERROR|WARN|INFO' logs/app.log | sort | uniq -c | sort -rn
خروجی
--- نام پروسه‌هایی که bash هستند (یکتا):
bash
--- کاربرهای دارای shell واقعی در /etc/passwd:
root:/bin/bash
sync:/bin/sync
ubuntu:/bin/bash
ali:/bin/bash
--- ۳ پرتکرارترین کلمه‌ی ERROR/WARN/INFO در لاگ:
5 INFO
3 ERROR
1 WARN

ترکیب grep با sort | uniq -c (درس قبل) یک تحلیل سریع می‌دهد. و در اسکریپت‌ها grep -q (quiet: چاپ نکن، فقط کد خروج) برای شرط به کار می‌رود:

Terminal window
if grep -q "ERROR" logs/error.log; then echo "خطا پیدا شد (کد خروج $?)"; fi
grep -q "FATAL" logs/error.log; echo "جستجوی FATAL: کد خروج $?"
grep "x" /no/such/file 2>/dev/null; echo "فایل ناموجود: کد خروج $?"
خروجی
خطا پیدا شد (کد خروج 0)
جستجوی FATAL: کد خروج 1
فایل ناموجود: کد خروج 2

کد خروج grep: ۰ یعنی حداقل یک تطبیق، ۱ یعنی تطبیقی نبود، ۲ یعنی خطا (مثلاً فایل نبود).

مثال ۹: فایل‌های باینری

Section titled “مثال ۹: فایل‌های باینری”
Terminal window
grep -r ERROR logs/archive
echo "--- با -a (به‌عنوان متن):"
grep -ra ERROR logs/archive | cat -v | cut -c1-60
echo "--- با -I (باینری‌ها را نادیده بگیر):"
grep -rI ERROR logs/archive; echo "کد خروج: $?"
خروجی
grep: logs/archive/data.bin: binary file matches
--- با -a (به‌عنوان متن):
logs/archive/data.bin:binary-ish^@data ERROR inside
--- با -I (باینری‌ها را نادیده بگیر):
کد خروج: 1

فایل data.bin حاوی بایت NUL است؛ grep آن را باینری می‌داند و فقط می‌گوید Binary file ... matches. -a آن را مثل متن می‌خواند (و cat -v کاراکتر NUL را ^@ نشان می‌دهد) و -I باینری‌ها را رد می‌کند. در جستجوی کد پروژه معمولاً -I می‌خواهی.

پشت پرده: regex چیست و grep چطور تطبیق می‌دهد؟

Section titled “پشت پرده: regex چیست و grep چطور تطبیق می‌دهد؟”

regex (regular expression) یک زبان کوچک برای توصیف الگوی متن است. grep الگو را به یک ماشین حالت (خودکار) تبدیل می‌کند و هر خط را از چپ به راست با آن مقایسه می‌کند؛ اگر جایی از خط با الگو بخواند، خط منطبق است (نه لزوماً کل خط؛ برای کل خط ^...$ بنویس). تطبیق حریصانه (greedy) است: * و + تا جایی که ممکن است ادامه می‌دهند. برای همین a.*b روی a1b2b تا آخرین b می‌رود.

سه دسته regex در لینوکس هست: BRE (پایه، پیش‌فرض grep؛ + ? | ( ) باید با \ بیایند)، ERE (grep -E؛ این نمادها مستقیم کار می‌کنند) و PCRE (grep -P؛ \d \w و lookahead). ابزارهای دیگر (sed، awk، vim) هم regex دارند و جزئیاتشان کمی فرق می‌کند، ولی اصول یکی است؛ چیزی که اینجا یاد می‌گیری در همه‌جا به کار می‌آید.

نکته‌ی مهم quote: الگو را همیشه داخل ' ' بگذار تا shell علامت‌های * ? [ ] $ \ را قبل از grep تفسیر نکند (درس shell و find).

flag کار
-i بی‌حساس به حروف
-n شماره‌ی خط
-c تعداد خط‌های منطبق
-v خط‌های غیرمنطبق
-w کلمه‌ی کامل
-o فقط بخش منطبق
-r بازگشتی در پوشه
-l / -L فقط اسم فایل‌های دارای / بدون تطبیق
-A N, -B N, -C N N خط بعد / قبل / دو طرف
-E regex توسعه‌یافته
-F متن ثابت (بدون regex)
-P regex پرل
-q بی‌صدا؛ فقط کد خروج
-m N بعد از N تطبیق بایست
-I / -a نادیده گرفتن باینری / خواندن به‌عنوان متن
--include, --exclude-dir فیلتر فایل‌ها در جستجوی بازگشتی
regex معنی مثال
. هر یک کاراکتر a.c
* صفر یا چند بار ab*c
+ (ERE) یک یا چند بار [0-9]+
? (ERE) صفر یا یک بار colou?r
^ / $ ابتدا / انتهای خط ^ERROR، done$
[abc] / [^abc] یکی از / هیچ‌یک از [0-9]
| (ERE) یا cat|dog
( ) (ERE) گروه (ab)+
{n,m} (ERE) تعداد تکرار [0-9]{1,3}
\. نقطه‌ی واقعی 1\.5

۱) فراموش کردن -E برای | و +

Section titled “۱) فراموش کردن -E برای | و +”
Terminal window
grep -c 'ERROR|WARN' logs/app.log
grep -cE 'ERROR|WARN' logs/app.log
خروجی
0
4

در BRE علامت | عادی است، پس الگوی «ERROR|WARN» دنبال همین متن می‌گردد و چیزی پیدا نمی‌شود (۰). راه‌حل: -E یا \|.

۲) نقطه در الگو بدون escape

Section titled “۲) نقطه در الگو بدون escape”

مثال ۷: 1.5 با 125 هم جور شد. راه‌حل: 1\.5 یا -F.

Terminal window
echo "ERROR از طریق pipe" | grep ERROR
echo "--- بدون فایل و بدون pipe، grep از stdin می‌خواند و منتظر تایپ می‌ماند (اینجا stdin را خالی می‌دهیم):"
grep ERROR < /dev/null; echo "کد خروج: $?"
خروجی
ERROR از طریق pipe
--- بدون فایل و بدون pipe، grep از stdin می‌خواند و منتظر تایپ می‌ماند (اینجا stdin را خالی می‌دهیم):
کد خروج: 1

اگر در ترمینال تعاملی grep ERROR را بدون فایل بزنی، ظاهراً «گیر» می‌کند، چون منتظر ورودی از صفحه‌کلید است (با Ctrl+C یا Ctrl+D خارج شو). راه‌حل: همیشه فایل یا pipe بده.

۴) ps aux | grep نام که خودِ grep را هم پیدا می‌کند

Section titled “۴) ps aux | grep نام که خودِ grep را هم پیدا می‌کند”
Terminal window
sleep 30 &
ps aux | grep "sleep 30" | awk '{print $11, $12, $13}'
echo "--- ترفند [s]leep:"
ps aux | grep "[s]leep 30" | awk '{print $11, $12, $13}'
kill $! 2>/dev/null
خروجی
sleep 30
grep sleep 30
--- ترفند [s]leep:
sleep 30

خط اول دو نتیجه داد (خود sleep و خود grep sleep 30). الگوی [s]leep خودِ grep را رد می‌کند (متن «[s]leep» با الگوی [s]leep جور نمی‌شود). بهتر: pgrep sleep (درس پروسه‌ها).

Terminal window
mkdir -p q && cd q
touch ERROR1 ERROR2
echo "ERROR line" > x.txt
echo "--- بدون quote (shell ERROR* را با ERROR1 ERROR2 جایگزین می‌کند):"
grep -c ERROR* x.txt
echo "--- با quote:"
grep -c 'ERROR*' x.txt
خروجی
--- بدون quote (shell ERROR* را با ERROR1 ERROR2 جایگزین می‌کند):
ERROR2:0
x.txt:0
--- با quote:
1

بدون quote، shell ERROR* را با اسم فایل‌های پوشه (ERROR1 و ERROR2) جایگزین کرد؛ پس grep الگوی ERROR1 را در فایل‌های ERROR2 و x.txt می‌جست و چیزی پیدا نکرد، بی‌هیچ خطایی. راه‌حل: الگو را داخل '...' بگذار.

✎ تمرینآسان

در logs/app.log خط‌های WARN را با شماره‌ی خط نشان بده و بگو چند خط INFO هست.

دیدن جواب
Terminal window
mkdir -p logs && printf 'a INFO x\nb WARN y\nc INFO z\n' > logs/app.log
grep -n WARN logs/app.log
echo "تعداد INFO: $(grep -c INFO logs/app.log)"
خروجی
2:b WARN y
تعداد INFO: 2
✎ تمرینمتوسط

تمرین اصلی: همه‌ی خط‌های ERROR را در لاگ‌های یک پوشه با شماره‌ی خط پیدا کن. پوشه‌ی logs (با دو فایل) را بساز و با grep -rn همه‌ی ERROR ها را بیاب، سپس فقط کلمه‌ی کامل ERROR (نه ERROR_CODE) را بشمار.

دیدن جواب
Terminal window
mkdir -p lg/sub
printf '1 INFO ok\n2 ERROR bad\n3 ERROR_CODE=5\n' > lg/a.log
printf 'ERROR in sub\nfine\n' > lg/sub/b.log
echo "--- همه‌ی ERROR ها با شماره‌ی خط:"
grep -rn "ERROR" lg
echo "--- فقط کلمه‌ی کامل ERROR: $(grep -rw "ERROR" lg | wc -l)"
خروجی
--- همه‌ی ERROR ها با شماره‌ی خط:
lg/a.log:2:2 ERROR bad
lg/a.log:3:3 ERROR_CODE=5
lg/sub/b.log:1:ERROR in sub
--- فقط کلمه‌ی کامل ERROR: 2
✎ تمرینسخت

از یک فایل متنی همه‌ی ایمیل‌ها و آدرس‌های IP را جداگانه استخراج کن، هر کدام یکتا و مرتب (با -oE، sort -u)، و تعداد IP های یکتا را بنویس. فایل را با چند خط مخلوط بساز.

دیدن جواب
Terminal window
cat > mix.txt <<'LXEOF'
contact: ali@example.com, sara@example.org
server 203.0.113.5 and 198.51.100.7 are up; 203.0.113.5 again
mail ali@example.com from 192.0.2.44
LXEOF
echo "--- ایمیل‌ها:"; grep -oE '[a-z]+@[a-z]+\.[a-z]+' mix.txt | sort -u
echo "--- IP ها:"; grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' mix.txt | sort -u
echo "تعداد IP یکتا: $(grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}' mix.txt | sort -u | wc -l)"
خروجی
--- ایمیل‌ها:
ali@example.com
sara@example.org
--- IP ها:
192.0.2.44
198.51.100.7
203.0.113.5
تعداد IP یکتا: 3
؟ آزمونک
  1. grep -v چه می‌کند؟

  2. کدام دستور در همه‌ی فایل‌های یک پوشه جستجو و شماره‌ی خط را نشان می‌دهد؟

  3. در regex، ^ و $ چه معنی دارند؟

  4. برای «ERROR یا WARN» چه می‌نویسی؟

  5. grep -o چه می‌دهد؟

  6. کد خروج grep وقتی هیچ تطبیقی پیدا نشود؟

  • grep الگو فایل...: flag های اصلی -i -n -c -v -w -o -r -l -A/-B/-C -m -q.
  • regex پایه: . هر کاراکتر، * تکرار، ^ $ ابتدا/انتها، [ ] مجموعه؛ با -E: + ? | ( ) { }؛ نقطه‌ی واقعی \.، یا -F برای متن ثابت.
  • -o + -E برای استخراج (IP، ایمیل، عدد)؛ ترکیب با sort | uniq -c.
  • الگو را در '...' بگذار؛ grep -q و کد خروج (۰/۱/۲) برای شرط‌ها.
  • باینری‌ها: -I نادیده بگیر، -a متن‌وار بخوان؛ برای نتیجه‌ی خودِ grep در ps aux | grep از [s]leep یا pgrep استفاده کن.
  • grep روی stdin هم کار می‌کند؛ در تقریباً هر pipeline هست.
برگه‌ی تقلب این درس
دستورکاری که می‌کند
grep ERROR fileخط‌های دارای ERROR
grep -i -n error fileبی‌حساس به حروف + شماره‌ی خط
grep -c ERROR fileتعداد خط‌های منطبق
grep -v DEBUG fileخط‌های بدون DEBUG
grep -rn "ERROR" dir/بازگشتی با شماره‌ی خط
grep -rl ERROR dir/فقط اسم فایل‌ها
grep -E "ERROR|WARN" fileیا (regex توسعه‌یافته)
grep -oE "[0-9]{1,3}(\.[0-9]{1,3}){3}" fاستخراج IP
grep -w ERROR fileکلمه‌ی کامل
grep -B2 -A2 ERROR fileدو خط قبل و بعد
grep -F "1.5" fileمتن ثابت (بدون regex)
grep -q text file && echo هستاستفاده در شرط (کد خروج)