بخش اول: معرفی پروژه
این پروژه یک اسکریپت Bash با منوی ساده است که یک فایل لاگ را میخواند، خطاها را میشمرد و یک گزارش متنی میسازد. کد روی Bash 5.2 اجرا و هر سه سناریو تست شده است.
۱. نام پروژه: تحلیلگر لاگ سیستم — Log Analyzer
۲. مسئله: سرورها و سیستمهای Linux هر اتفاقی را در فایلهای لاگ ثبت میکنند. این فایلها صدها خط دارند و پیدا کردن خطاهای مهم با چشم سخت است. مدیر سیستم باید سریع بفهمد چند خطا رخ داده و کدام خطا بیشتر تکرار شده.
۳. هدف: ساختن ابزاری کوچک که با چند انتخاب از منو، خلاصهٔ وضعیت لاگ را نشان دهد و نتیجه را در یک فایل گزارش ذخیره کند.
۴. قابلیتهای اصلی:
- نمایش خلاصه: تعداد کل خطوط و تعداد INFO، WARNING و ERROR
- نمایش فقط خطوط ERROR
- جستوجوی یک کلمه که کاربر تایپ میکند
- نمایش ۳ خطای پرتکرار
- ذخیرهٔ گزارش در پوشهٔ
reports - مدیریت خطا: نبودن آرگومان، نبودن فایل، فایل خالی، انتخاب نامعتبر از منو
۵. دستورات و مفاهیم استفادهشده:
| نوع | موارد |
|---|---|
| دستورات آشنا | echo، grep، cut، sort، head، wc، mkdir، chmod، ls، cat |
| دستورات جدید | uniq -c، date، read -p |
| مفاهیم جدید Bash | shebang، متغیر، آرگومان $1 و $#، شرط if و تست فایل، کد خروج و exit، تابع و local، $( )، هدایت > و >> و <، pipe، حلقهٔ while، دستور case |
۶. مفاهیم جدیدی که یاد میگیری: نوشتن اسکریپت قابل اجرا، گرفتن آرگومان، بررسی وجود فایل، تابع، منوی تکرارشونده با while و case، ترکیب چند دستور با pipe برای شمارش تکرارها، و ذخیرهٔ خروجی در فایل.
۷. زمان تقریبی آمادهسازی:
| کار | زمان |
|---|---|
| ساخت محیط و تایپ کد | ۳۰ دقیقه |
| خواندن آموزش دستورات جدید | ۴۵ دقیقه |
| اجرای سناریوها و فهم کد | ۴۵ دقیقه |
| تمرین ارائه و سؤالات | ۶۰ دقیقه |
| جمع | حدود ۳ ساعت |
بخش دوم: پیشنیازها و ساخت محیط آزمایش
پیشنیاز فقط یک ترمینال Ubuntu است. همهٔ دستورات پیشفرض نصب هستند، اینترنت و sudo لازم نیست. ساختار نهایی پوشه این میشود:
~/log_project/
├── log_analyzer.sh ← اسکریپت اصلی
├── logs/
│ ├── server.log ← لاگ نمونه (۱۶ خط)
│ └── empty.log ← فایل خالی برای تست خطا
└── reports/ ← خود اسکریپت میسازد
گام ۱ — ساخت پوشهها (در هر مسیری اجرا کنی، چون ~ یعنی پوشهٔ خانه):
mkdir -p ~/log_project/logs
cd ~/log_project
pwd
خروجی pwd چیزی شبیه /home/amin/log_project است. از اینجا به بعد همهٔ دستورات را داخل ~/log_project اجرا کن.
گام ۲ — ساخت لاگ نمونه. کل این بلوک را یکجا کپی و در ترمینال Paste کن. ساختار << 'EOF' اسمش here-document است: همهٔ خطوط تا EOF را به cat میدهد و > آنها را در فایل مینویسد.
cat > logs/server.log << 'EOF'
2026-11-01 08:00:01 INFO System boot completed
2026-11-01 08:00:15 INFO User ali logged in
2026-11-01 08:05:42 WARNING CPU usage above 80%
2026-11-01 08:10:03 ERROR Disk space low on /home
2026-11-01 08:12:27 INFO User sara logged in
2026-11-01 08:15:10 ERROR Failed login for user root
2026-11-01 08:15:45 ERROR Failed login for user root
2026-11-01 08:20:00 INFO Backup started
2026-11-01 08:25:33 WARNING Memory usage above 70%
2026-11-01 08:30:12 ERROR Disk space low on /home
2026-11-01 08:31:08 INFO Backup finished
2026-11-01 08:40:19 ERROR Failed login for user root
2026-11-01 08:45:00 WARNING CPU usage above 80%
2026-11-01 08:50:21 INFO User ali logged out
2026-11-01 08:55:37 ERROR Service nginx stopped unexpectedly
2026-11-01 09:00:00 INFO System health check passed
EOF
گام ۳ — ساخت فایل خالی و بررسی:
touch logs/empty.log
ls logs
wc -l logs/server.log
خروجی مورد انتظار:
empty.log server.log
16 logs/server.log
گام ۴ — ساخت اسکریپت. با nano log_analyzer.sh فایل را باز کن، کد بخش چهارم را Paste کن و با Ctrl+O، Enter، Ctrl+X ذخیره کن. بعد:
chmod +x log_analyzer.sh
ls -l log_analyzer.sh
در خروجی باید -rwxr-xr-x ببینی؛ حرف x یعنی فایل اجرایی شده.
نکته: چون آزمایشگاه اینترنت ندارد، کل پوشهٔ
log_projectرا روی فلش ببر. اگر فایل از فلش کپی شد، یک بار دیگرchmod +xرا اجرا کن.
بخش سوم: آموزش دستورات و مفاهیم جدید
۱۱ مفهوم جدید در این پروژه است. همهٔ مثالها اجرا شدهاند و خروجیها واقعی هستند. مثالها را داخل ~/log_project اجرا کن.
۱. Shebang (#!/bin/bash)
- کاربرد: اولین خط اسکریپت است و به سیستم میگوید این فایل را با برنامهٔ
/bin/bashاجرا کن. - شکل کلی:
#!/bin/bashدقیقاً در خط اول - نقش در پروژه: به لطف آن اسکریپت را با
./log_analyzer.shاجرا میکنیم نهbash log_analyzer.sh.
۲. متغیر و جایگذاری خروجی دستور $( )
- کاربرد: متغیر یک مقدار را نگه میدارد.
$(دستور)خروجی یک دستور را بهجای خودش میگذارد. - شکل کلی:
name=value(بدون فاصله کنار=)، خواندن با"$name" - مثال:
name="Amin"
echo "Hello $name"
today=$(date +%Y-%m-%d)
echo "Today is $today"
- خروجی:
Hello Amin
Today is 2026-11-01
- نقش در پروژه:
REPORT_DIRوLOG_FILEمتغیرند؛ تعداد خطوط و نام فایل گزارش با$( )ساخته میشوند.
۳. آرگومانهای اسکریپت ($0، $1، $#)
- کاربرد: چیزی که بعد از نام اسکریپت مینویسیم به آن داده میشود.
$0نام خود اسکریپت،$1اولین آرگومان و$#تعداد آرگومانها است. - شکل کلی:
./script.sh arg1 arg2 - مثال: فایل
args.sh:
#!/bin/bash
echo "Script name: $0"
echo "First arg : $1"
echo "Arg count : $#"
- خروجی با
bash args.sh logs/server.log:
Script name: args.sh
First arg : logs/server.log
Arg count : 1
- نقش در پروژه: مسیر فایل لاگ با
$1گرفته میشود؛ پس ابزار با هر فایل لاگی کار میکند.
۴. شرط if و تستهای [ ]
- کاربرد: اگر شرط درست بود یک کار و اگر نه کار دیگری انجام میدهد.
- شکل کلی:
if [ condition ]; then
commands
else
commands
fi
- تستهای این پروژه (فاصلهٔ کنار
[و]اجباری است):
| تست | معنی |
|---|---|
-f file |
فایل وجود دارد |
-s file |
فایل خالی نیست |
-z "$var" |
متغیر خالی است |
a -ne b |
عدد a با b برابر نیست (not equal) |
! |
برعکس کردن شرط |
- مثال:
if [ -f logs/server.log ]; then
echo "File exists"
else
echo "File not found"
fi
- خروجی:
File exists - نقش در پروژه: قبل از شروع، تعداد آرگومان، وجود فایل و خالی نبودن آن را چک میکنیم.
۵. کد خروج (exit و $?)
- کاربرد: هر دستور بعد از اجرا یک عدد برمیگرداند.
0یعنی موفق و غیر صفر یعنی خطا.$?کد آخرین دستور را نشان میدهد. - شکل کلی:
exit 0،exit 1،echo $? - مثال:
ls logs/nothing.log
echo "Exit code: $?"
- خروجی:
ls: cannot access 'logs/nothing.log': No such file or directory
Exit code: 2
- نقش در پروژه: هر خطا کد جدا دارد: بدون آرگومان
1، نبودن فایل2، فایل خالی3، خروج عادی0.
۶. تابع (Function) و local
- کاربرد: یک تکه کد را اسمگذاری میکنیم تا بارها صدایش بزنیم.
localمتغیری میسازد که فقط داخل همان تابع وجود دارد.returnاز تابع بیرون میآید اما برنامه را تمام نمیکند. - شکل کلی:
function_name() {
commands
}
function_name arg1
- مثال:
greet() {
local person="$1"
echo "Hi $person"
}
greet Sara
- خروجی:
Hi Sara - نقش در پروژه: هر گزینهٔ منو یک تابع است (
show_summary،show_errors، ...). داخل تابع،$1یعنی آرگومان خود تابع نه اسکریپت.
۷. دریافت ورودی با read -p
- کاربرد: یک پیام نشان میدهد، منتظر تایپ کاربر میماند و بعد از Enter متن را در متغیر میریزد.
- شکل کلی:
read -p "message" variable - مثال:
read -p "Your name: " userو بعدecho "Welcome $user" - خروجی (اگر Ali تایپ کنی):
Your name: Aliو بعدWelcome Ali - نقش در پروژه: گرفتن شمارهٔ منو و کلمهٔ جستوجو.
۸. حلقهٔ while true و دستور case
- کاربرد:
while trueکد داخلش را بینهایت بار تکرار میکند تا باexitخارج شویم.caseیک مقدار را با چند حالت مقایسه میکند و جایگزین چندifپشت سر هم است. - شکل کلی:
case "$var" in
1) commands ;;
2) commands ;;
*) default ;;
esac
;; پایان هر حالت است و * یعنی «هر چیز دیگر».
- مثال:
choice=2
case "$choice" in
1) echo "One" ;;
2) echo "Two" ;;
*) echo "Unknown" ;;
esac
- خروجی:
Two - نقش در پروژه: منو بعد از هر انتخاب دوباره نمایش داده میشود و
caseتابع مناسب را صدا میزند.
۹. هدایت ورودی و خروجی (>، >>، <)
- کاربرد:
>خروجی را در فایل مینویسد و محتوای قبلی را پاک میکند.>>به انتهای فایل اضافه میکند.<فایل را به ورودی دستور میدهد. - مثال:
echo "first" > test.txt
echo "second" >> test.txt
cat test.txt
wc -l < test.txt
- خروجی:
first
second
2
- نقش در پروژه: خط اول گزارش با
>نوشته میشود (پس با هر اجرا گزارش تازه میشود) و بقیه با>>. باwc -l <فقط عدد چاپ میشود نه نام فایل.
۱۰. Pipe و دستور uniq -c
- کاربرد:
|خروجی یک دستور را ورودی دستور بعدی میکند.uniq -cخطوط تکراری پشتسرهم را یکی میکند و تعدادشان را کنارشان مینویسد. به همین دلیل قبلش حتماًsortمیآید.sort -nrیعنی مرتبسازی عددی (n) و برعکس (r)، از بزرگ به کوچک. - شکل کلی:
command1 | command2 | command3 - مثال:
printf 'b\na\nb\nc\nb\n' | sort | uniq -c | sort -nr
- خروجی:
3 b
1 c
1 a
- نقش در پروژه: قلب قابلیت «۳ خطای پرتکرار» همین زنجیره است.
۱۱. دستور date و گزینههای تازهٔ grep
date: تاریخ و ساعت را با قالب دلخواه چاپ میکند.date +%Y-%m-%dخروجی2026-11-01وdate '+%H:%M:%S'خروجی مثل22:24:10میدهد. در پروژه نام فایل گزارش و زمان ساختش را میسازد.grep -c: بهجای چاپ خطوط، تعدادشان را میدهد.grep -c " ERROR " logs/server.logخروجی6میدهد.grep -i: جستوجو بدون توجه به حروف کوچک و بزرگ؛rootوROOTهر دو پیدا میشوند.grep --: به grep میگوید بعد از این دیگر گزینه نیست. اگر کاربر کلمهٔیی مثل-vتایپ کند، بهجای گزینه کلمه حساب میشود.- ادامهٔ
cut:cut -d' ' -f4-یعنی با جداکنندهٔ فاصله، از ستون چهارم تا آخر. از... ERROR Disk space low on /homeفقطDisk space low on /homeمیماند.
بخش چهارم: کد کامل پروژه
نام فایل اصلی log_analyzer.sh است و در ~/log_project قرار میگیرد. کد ۱۰۹ خط است، فقط از دستورات پیشفرض Ubuntu استفاده میکند، هیچ فایلی پاک نمیکند و فقط در پوشهٔ reports مینویسد.
#!/bin/bash
# ============================================================
# Log Analyzer
# Usage: ./log_analyzer.sh <log_file>
# Example: ./log_analyzer.sh logs/server.log
# Log line format: DATE TIME LEVEL MESSAGE
# e.g. 2026-11-01 08:10:03 ERROR Disk space low on /home
# ============================================================
# ---------- 1) Settings (variables) ----------
REPORT_DIR="reports"
LOG_FILE="$1"
# ---------- 2) Check the input argument ----------
if [ $# -ne 1 ]; then
echo "Usage: $0 <log_file>"
echo "Example: $0 logs/server.log"
exit 1
fi
if [ ! -f "$LOG_FILE" ]; then
echo "Error: file '$LOG_FILE' not found."
exit 2
fi
if [ ! -s "$LOG_FILE" ]; then
echo "Error: file '$LOG_FILE' is empty."
exit 3
fi
# ---------- 3) Functions ----------
# Count lines that have a given level (INFO / WARNING / ERROR)
count_level() {
local level="$1"
grep -c " $level " "$LOG_FILE"
}
# Show a short summary of the log file
show_summary() {
local total=$(wc -l < "$LOG_FILE")
echo "------ Summary of $LOG_FILE ------"
echo "Total lines : $total"
echo "INFO : $(count_level INFO)"
echo "WARNING : $(count_level WARNING)"
echo "ERROR : $(count_level ERROR)"
}
# Show only ERROR lines
show_errors() {
echo "------ ERROR lines ------"
grep " ERROR " "$LOG_FILE"
}
# Search for a word that the user types
search_keyword() {
read -p "Enter a word to search: " keyword
if [ -z "$keyword" ]; then
echo "Error: you did not enter any word."
return
fi
echo "------ Lines containing '$keyword' ------"
if ! grep -i -- "$keyword" "$LOG_FILE"; then
echo "No result found for '$keyword'."
fi
}
# Show the 3 most repeated error messages
top_errors() {
echo "------ Top 3 repeated errors ------"
grep " ERROR " "$LOG_FILE" | cut -d' ' -f4- | sort | uniq -c | sort -nr | head -3
}
# Save summary + top errors into a report file
save_report() {
mkdir -p "$REPORT_DIR"
local report_file="$REPORT_DIR/report_$(date +%Y-%m-%d).txt"
echo "Report created at: $(date '+%Y-%m-%d %H:%M:%S')" > "$report_file"
show_summary >> "$report_file"
top_errors >> "$report_file"
echo "Report saved to: $report_file"
}
# ---------- 4) Main menu (loop) ----------
while true; do
echo
echo "========= Log Analyzer ========="
echo "1) Show summary"
echo "2) Show ERROR lines"
echo "3) Search a word"
echo "4) Top 3 repeated errors"
echo "5) Save report"
echo "0) Exit"
read -p "Your choice: " choice
case "$choice" in
1) show_summary ;;
2) show_errors ;;
3) search_keyword ;;
4) top_errors ;;
5) save_report ;;
0) echo "Goodbye!"; exit 0 ;;
*) echo "Invalid choice. Please enter a number from 0 to 5." ;;
esac
done
بررسی منطقی: با bash -n خطای نحوی ندارد، روی GNU bash 5.2 (همان نسخهٔ Ubuntu 24.04) اجرا شده، نیازی به sudo و اینترنت ندارد، و اجرای مجدد همان نتیجه را میدهد چون گزارش هر روز با > بازنویسی میشود و mkdir -p اگر پوشه باشد خطا نمیدهد.
بخش پنجم: توضیح بخشبهبخش کد
کد چهار بخش اصلی دارد که با کامنت ---------- جدا شدهاند: تنظیمات، بررسی ورودی، توابع، و منوی اصلی. ترتیب اجرا هم همین است: اول چک میکند فایل درست است، بعد منو را تا وقتی 0 زده نشده تکرار میکند.
بخش ۰ — سربرگ (خط ۱ تا ۸)
- چه میکند: خط اول shebang است؛ بقیه کامنتاند و نحوهٔ اجرا و قالب لاگ را میگویند.
- چرا: هر کس فایل را باز کند بدون خواندن کد میفهمد چطور استفادهاش کند.
- اگر حذف شود: بدون shebang معلوم نیست فایل با کدام shell اجرا شود. اگر با
shاجرا شود (که در Ubuntu همانdashاست)، دستوری مثلread -pکار نمیکند. کامنتها تأثیری در اجرا ندارند.
بخش ۱ — تنظیمات (REPORT_DIR و LOG_FILE)
- چه میکند: نام پوشهٔ گزارش و مسیر فایل لاگ (از
$1) را در دو متغیر میریزد. - چرا: اگر بخواهیم مسیر گزارش را عوض کنیم، فقط یک خط تغییر میکند. اسم
LOG_FILEهم از$1خواناتر است. - مفهوم: متغیر، آرگومان
$1. - اگر تغییر کند: با
REPORT_DIR="output"گزارشها در پوشهٔoutputساخته میشوند.
بخش ۲ — بررسی ورودی (سه if)
- چه میکند: سه چیز را پشت سر هم چک میکند: دقیقاً یک آرگومان داده شده (
$# -ne 1)، فایل وجود دارد (! -f)، و خالی نیست (! -s). اگر هرکدام غلط باشد، پیام میدهد و با کد خاص خارج میشود. - چرا: به این روش «اول ورودی را چک کن، بعد کار کن» میگویند. باقی کد مطمئن است فایل سالم است و لازم نیست در هر تابع دوباره چک کند.
- مفهوم:
if،[ ]،-ne،-f،-s،!،exit. - اگر حذف شود: اگر فایل نباشد، منو باز میشود ولی هر گزینه خطای زشت
grep: No such file or directoryمیدهد. - نکته:
"$LOG_FILE"داخل گیومه است تا اگر نام فایل فاصله داشت، دو تکه نشود.
بخش ۳الف — count_level و show_summary
- چه میکند:
count_levelیک سطح (مثلERROR) میگیرد و باgrep -cتعداد خطوط آن را برمیگرداند.show_summaryکل خطوط را باwc -lمیشمرد و سه بارcount_levelرا صدا میزند. - چرا تابع جدا: بهجای سه بار نوشتن یک دستور، یک بار نوشته و سه بار صدا زده شده.
- چرا فاصله دور
" $level ": تا فقط کلمهٔ کامل پیدا شود؛ مثلاً کلمهٔیی مثلERRORSدر متن پیام شمرده نشود. - چرا
wc -l <: با<فقط عدد16چاپ میشود؛ بدون آن خروجی16 logs/server.logمیشد. - مفهوم: تابع،
local،$( )،grep -c،<.
بخش ۳ب — show_errors
- چه میکند: فقط خطوط دارای
ERRORرا چاپ میکند. - چرا: مدیر سیستم اول از همه خطاها را میخواهد ببیند، نه INFO ها.
- اگر تغییر کند: با
grep -nشمارهٔ خط هم کنار هر خطا میآید.
بخش ۳پ — search_keyword
- چه میکند: با
read -pیک کلمه میگیرد. اگر خالی باشد (-z) پیام خطا میدهد و باreturnبه منو برمیگردد. اگر نباشد، باgrep -iجستوجو میکند. - نکتهٔ اصلی (
if ! grep):ifفقط با[ ]کار نمیکند؛ میتواند کد خروج هر دستوری را چک کند.grepاگر چیزی پیدا کند کد0و اگر نه کد1میدهد.!برعکسش میکند، پس پیام «پیدا نشد» فقط وقتی چاپ میشود که نتیجهای نباشد. - چرا
returnنهexit:exitکل برنامه را میبندد؛ ما فقط میخواهیم به منو برگردیم. - اگر تغییر کند: بدون
-i، جستوجویRootچیزی پیدا نمیکند. بدون--، تایپ-vباعث میشود grep آن را گزینه بفهمد.
بخش ۳ت — top_errors (مهمترین خط)
این یک خط پنج pipe دارد. داده مرحلهبهمرحله اینطور عوض میشود:
| مرحله | دستور | خروجی این مرحله |
|---|---|---|
| ۱ | grep " ERROR " |
۶ خط خطا، با تاریخ و ساعت |
| ۲ | cut -d' ' -f4- |
فقط متن خطا، مثل Failed login for user root |
| ۳ | sort |
متنهای یکسان کنار هم میآیند |
| ۴ | uniq -c |
هر متن یک بار با تعدادش: 3 Failed login...، 2 Disk space...، 1 Service nginx... |
| ۵ | sort -nr |
از بیشترین به کمترین |
| ۶ | head -3 |
فقط سه مورد اول |
- چرا اول
cut: هر خط زمان متفاوتی دارد؛ اگر تاریخ حذف نشود، هیچ دو خطی یکسان نیستند و همه تعداد1میگیرند. - اگر
sortاول حذف شود:uniqفقط تکراریهای پشتسرهم را میشمارد و نتیجه غلط میشود.
بخش ۳ث — save_report
- چه میکند: پوشهٔ
reportsرا میسازد (اگر نباشد)، نام فایل را با تاریخ امروز میسازد، خط اول را با>مینویسد، و خروجی دو تابع دیگر را با>>اضافه میکند. - نکتهٔ جالب: خروجی یک تابع را هم مثل یک دستور معمولی میشود در فایل ریخت. به همین خاطر برای گزارش کد جدیدی ننوشتیم.
- اگر اولی هم
>>باشد: با هر بار ذخیره، گزارش جدید زیر قبلی اضافه میشود و فایل بزرگ میشود. - اگر
-pحذف شود: بار دوم که پوشه وجود دارد،mkdirخطایFile existsمیدهد.
بخش ۴ — منوی اصلی (while + case)
- چه میکند: منو را چاپ میکند، انتخاب کاربر را میگیرد و
caseتابع مربوط را صدا میزند.while trueباعث میشود بعد از هر کار، منو دوباره بیاید. - تنها راه خروج: گزینهٔ
0کهexit 0میزند (یاCtrl+C). *): هر ورودی دیگری (9،abc، خالی) به اینجا میرسد و پیام خطا میدهد؛ برنامه نمیشکند.- اگر
whileحذف شود: برنامه فقط یک کار انجام میدهد و تمام میشود. - اگر
*)حذف شود: ورودی غلط هیچ پیامی نمیدهد و کاربر نمیفهمد چه شد.
بخش ششم: اجرای عملی و آزمایش پروژه
همهٔ خروجیهای این بخش از اجرای واقعی اسکریپت کپی شدهاند. برای کوتاه شدن، منوی تکراری فقط یک بار نشان داده شده.
اجرا (داخل ~/log_project):
cd ~/log_project
./log_analyzer.sh logs/server.log
منویی که باید ببینی:
========= Log Analyzer =========
1) Show summary
2) Show ERROR lines
3) Search a word
4) Top 3 repeated errors
5) Save report
0) Exit
Your choice:
سناریوی ۱ — اجرای عادی و موفق
ورودیها به ترتیب: 1، 2، 4، 5، 0
Your choice: 1
------ Summary of logs/server.log ------
Total lines : 16
INFO : 7
WARNING : 3
ERROR : 6
Your choice: 2
------ ERROR lines ------
2026-11-01 08:10:03 ERROR Disk space low on /home
2026-11-01 08:15:10 ERROR Failed login for user root
2026-11-01 08:15:45 ERROR Failed login for user root
2026-11-01 08:30:12 ERROR Disk space low on /home
2026-11-01 08:40:19 ERROR Failed login for user root
2026-11-01 08:55:37 ERROR Service nginx stopped unexpectedly
Your choice: 4
------ Top 3 repeated errors ------
3 Failed login for user root
2 Disk space low on /home
1 Service nginx stopped unexpectedly
Your choice: 5
Report saved to: reports/report_2026-11-01.txt
Your choice: 0
Goodbye!
بعد از خروج، گزارش را نشان بده (تاریخ و ساعت در آزمایشگاه همان روز است):
ls reports
cat reports/report_*.txt
report_2026-11-01.txt
Report created at: 2026-11-01 22:23:08
------ Summary of logs/server.log ------
Total lines : 16
INFO : 7
WARNING : 3
ERROR : 6
------ Top 3 repeated errors ------
3 Failed login for user root
2 Disk space low on /home
1 Service nginx stopped unexpectedly
سناریوی ۲ — جستوجو با ورودیهای متفاوت
ورودیها: گزینهٔ 3 چهار بار، با کلمههای root، backup، kernel و یک بار فقط Enter
Your choice: 3
Enter a word to search: root
------ Lines containing 'root' ------
2026-11-01 08:15:10 ERROR Failed login for user root
2026-11-01 08:15:45 ERROR Failed login for user root
2026-11-01 08:40:19 ERROR Failed login for user root
Your choice: 3
Enter a word to search: backup
------ Lines containing 'backup' ------
2026-11-01 08:20:00 INFO Backup started
2026-11-01 08:31:08 INFO Backup finished
Your choice: 3
Enter a word to search: kernel
------ Lines containing 'kernel' ------
No result found for 'kernel'.
Your choice: 3
Enter a word to search:
Error: you did not enter any word.
نکتهٔ نمایشی: backup با حروف کوچک تایپ شده ولی Backup پیدا شد؛ این کار -i است.
سناریوی ۳ — وضعیتهای نامعتبر
بعد از هر دستور، echo $? را بزن تا کد خروج را ببینی.
| حالت | دستور | خروجی | $? |
|---|---|---|---|
| بدون آرگومان | ./log_analyzer.sh |
Usage: ./log_analyzer.sh <log_file> و Example: ./log_analyzer.sh logs/server.log |
1 |
| فایل ناموجود | ./log_analyzer.sh logs/nothing.log |
Error: file 'logs/nothing.log' not found. |
2 |
| فایل خالی | ./log_analyzer.sh logs/empty.log |
Error: file 'logs/empty.log' is empty. |
3 |
| انتخاب غلط در منو | اجرای عادی و وارد کردن 9 یا abc |
Invalid choice. Please enter a number from 0 to 5. و منو دوباره میآید |
برنامه ادامه میدهد |
مثال:
$ ./log_analyzer.sh logs/nothing.log
Error: file 'logs/nothing.log' not found.
$ echo $?
2
بخش هفتم: برنامهٔ ارائهٔ ۹ دقیقهای
ارائه ۸ دقیقه و ۳۰ ثانیه است و ۳۰ ثانیه برای تأخیر خالی میماند. قبل از شروع، ترمینال را در ~/log_project باز نگه دار و فونت را با Ctrl+Shift+= بزرگ کن.
| بخش | زمان | زمان تجمعی |
|---|---|---|
| ۱. معرفی مسئله و هدف | ۱:۰۰ | ۱:۰۰ |
| ۲. دستورات و مفاهیم جدید | ۲:۰۰ | ۳:۰۰ |
| ۳. ساختار کد | ۱:۳۰ | ۴:۳۰ |
| ۴. اجرای عملی | ۳:۰۰ | ۷:۳۰ |
| ۵. نتیجه و جمعبندی | ۱:۰۰ | ۸:۳۰ |
۱. معرفی مسئله و هدف (۱ دقیقه)
«سلام. پروژهٔ من یک تحلیلگر لاگ با Bash است. در لینوکس تقریباً همهٔ سرویسها اتفاقاتشان را در فایل لاگ مینویسند، مثل ورود کاربر، هشدار و خطا. این فایلها معمولاً هزاران خط دارند و مدیر سیستم نمیتواند همه را بخواند. سؤال اصلی او این است: چند خطا داشتیم و کدام خطا بیشتر تکرار شده؟ ابزار من همین سؤال را با یک منوی ساده جواب میدهد و نتیجه را در یک فایل گزارش ذخیره میکند. کاملاً آفلاین است و sudo لازم ندارد.»
همزمان cat logs/server.log را اجرا کن و بگو: «هر خط چهار بخش دارد: تاریخ، ساعت، سطح و پیام.»
۲. دستورات و مفاهیم جدید (۲ دقیقه)
«برای این پروژه چند مفهوم جدید یاد گرفتم. اول آرگومان: مسیر فایل لاگ با
$1به اسکریپت داده میشود، پس ابزار با هر فایلی کار میکند. دومifبا تست فایل:-fمیپرسد فایل هست؟ و-sمیپرسد خالی نیست؟ سوم کد خروج: هر برنامه آخر کار یک عدد برمیگرداند؛ صفر یعنی موفق. من برای هر خطا یک کد جدا گذاشتم. چهارم تابع: هر گزینهٔ منو یک تابع است که کد مرتب و قابل استفادهٔ دوباره باشد. پنجمwhileوcase: منو داخل یک حلقهٔ بیپایان است وcaseانتخاب کاربر را به تابع درست میفرستد. و آخرuniq -c: خطوط تکراری را میشمارد، البته فقط وقتی پشت سر هم باشند؛ برای همین قبلش sort میکنم.»
۳. ساختار کد (۱ دقیقه و ۳۰ ثانیه)
فایل را با cat log_analyzer.sh یا در ویرایشگر نشان بده و فقط روی چهار بخش اشاره کن:
«کد چهار بخش دارد. اول دو متغیر تنظیمات. بعد سه بررسی ورودی؛ ایده این است که اول ورودی را چک کنیم تا بقیهٔ کد با خیال راحت کار کند. بخش سوم شش تابع است. مهمترینشان
top_errorsاست که با یک خط pipe کار میکند: grep خطاها را جدا میکند، cut تاریخ را حذف میکند تا خطاهای یکسان واقعاً یکسان شوند، sort و uniq میشمارند، و sort -nr و head سه تای اول را میدهند. بخش آخر منوی اصلی است.»
۴. اجرای عملی (۳ دقیقه)
./log_analyzer.sh logs/server.log→ گزینهٔ1: «۱۶ خط، ۶ خطا.»- گزینهٔ
4: «مهمترین مشکل سه ورود ناموفق root است؛ یعنی احتمالاً کسی رمز را حدس میزند.» - گزینهٔ
3باbackup: «با حرف کوچک نوشتم ولی پیدا شد، به خاطر-i.» - گزینهٔ
9: «ورودی غلط برنامه را نمیشکند.» - گزینهٔ
5، بعد0، بعدcat reports/report_*.txt. ./log_analyzer.sh logs/nothing.logوecho $?: «خطا و کد خروج ۲.»
۵. نتیجه و جمعبندی (۱ دقیقه)
«در این پروژه دیدیم که با ترکیب چند دستور ساده مثل grep و sort و uniq با pipe، میشود یک ابزار واقعی ساخت. از مفاهیم جدید مثل آرگومان، شرط، تابع، حلقه و کد خروج استفاده کردم و ورودیهای غلط را هم مدیریت کردم. این ابزار میتواند با تغییر کوچک روی لاگهای واقعی سیستم هم کار کند. ممنون از توجهتان.»
بخش هشتم: سؤالات احتمالی استاد
۱۱ سؤال با پاسخ. سه سؤال آخر دربارهٔ تغییر کد است و کدشان تست شده.
۱. هدف این پروژه چیست؟ به مدیر سیستم کمک میکند بدون خواندن کل فایل لاگ، تعداد خطاها و پرتکرارترینشان را ببیند و گزارش ذخیره کند.
۲. چرا قبل از uniq -c از sort استفاده کردی؟ uniq فقط خطوط تکراری پشتسرهم را یکی میکند. در لاگ ما Disk space low در خط ۴ و ۱۰ آمده؛ بدون sort دو بار با تعداد ۱ شمرده میشد.
۳. چرا cut -d' ' -f4- لازم است؟ چون هر خط تاریخ و ساعت مختلفی دارد. اگر حذفشان نکنیم، هیچ دو خطی یکسان نیست و همه تعداد ۱ میگیرند. -f4- یعنی از ستون چهارم تا آخر؛ چون پیام خودش چند کلمه است.
۴. فرق $1 بیرون و داخل تابع چیست؟ بیرون تابع، $1 اولین آرگومان اسکریپت است (مسیر لاگ). داخل count_level، $1 آرگومان خود تابع است (مثلاً ERROR). به همین دلیل مسیر لاگ را اول کار در LOG_FILE ذخیره کردم.
۵. فرق exit و return چیست؟ exit کل اسکریپت را تمام میکند؛ return فقط از تابع بیرون میآید. در search_keyword اگر ورودی خالی باشد return زدم تا کاربر به منو برگردد، نه اینکه برنامه بسته شود.
۶. خطاها را چطور مدیریت کردی؟ پنج حالت: بدون آرگومان (کد ۱)، فایل ناموجود (کد ۲)، فایل خالی (کد ۳)، کلمهٔ جستوجوی خالی، و انتخاب نامعتبر از منو با *). سه حالت اول برنامه را میبندند چون بدون فایل کاری نمیشود کرد؛ دو حالت آخر فقط پیام میدهند.
۷. اگر برنامه را دو بار اجرا کنیم و دو بار گزارش بگیریم چه میشود؟ در یک روز، همان فایل بازنویسی میشود چون خط اول با > نوشته میشود؛ فقط ساعت داخلش عوض میشود. در روز دیگر فایل جدیدی با تاریخ تازه ساخته میشود. mkdir -p هم بار دوم خطا نمیدهد.
۸. محدودیتهای پروژه چیست؟
- فقط لاگهایی با قالب
DATE TIME LEVEL MESSAGEرا درست میفهمد؛ لاگهای واقعی مثل/var/log/syslogقالب دیگری دارند. - اگر متن پیام خودش کلمهٔ
ERRORداشته باشد، اشتباه شمرده میشود. - فقط یک فایل در هر اجرا بررسی میشود.
۹. (تغییر کد) اگر بخواهیم ۵ خطای پرتکرار نشان دهد چه کار کنیم؟ در top_errors، head -3 را head -5 میکنیم. بهتر است بالای فایل متغیر TOP_COUNT=5 بسازیم و بنویسیم head -"$TOP_COUNT" تا فقط یک جا عوض شود. متن عنوان و منو هم باید از Top 3 به Top 5 تغییر کند.
۱۰. (توسعهٔ کد) یک گزینهٔ جدید برای نمایش WARNING اضافه کن. سه کار: یک تابع میسازیم، یک خط به منو و یک حالت به case اضافه میکنیم:
show_warnings() {
echo "------ WARNING lines ------"
grep " WARNING " "$LOG_FILE"
}
# in the menu:
echo "6) Show WARNING lines"
# in case:
6) show_warnings ;;
پیام *) هم باید به from 0 to 6 تغییر کند. این نشان میدهد چرا تابع مفید است: اضافه کردن قابلیت به بقیهٔ کد دست نمیزند.
۱۱. (توسعهٔ کد) بدون نوشتن نام سطحها، تعداد همهٔ سطحها را بشمار. با awk ستون سوم را جدا میکنیم و همان زنجیرهٔ شمارش را میزنیم:
awk '{print $3}' logs/server.log | sort | uniq -c | sort -nr
7 INFO
6 ERROR
3 WARNING
مزیتش این است که اگر سطح جدیدی مثل DEBUG در لاگ بیاید، خودکار شمرده میشود.
بخش نهم: چکلیست آمادگی
شب قبل از آزمایشگاه این موارد را تیک بزن:
- پوشهٔ
log_projectباlog_analyzer.sh،logs/server.logوlogs/empty.logروی فلش است - پروژه را یک بار با اینترنت قطع اجرا کردهام و کار کرد
-
ls -lنشان میدهد فایل اسکریپتxدارد (اگر نه:chmod +x log_analyzer.sh) - هر سه سناریوی بخش ششم را اجرا کردهام و خروجیها یکی بودند
- دستورات آشنا (
grep،cut،sort،head،wc،mkdir) را بدون نگاه توضیح میدهم - مفاهیم جدید را میفهمم:
$1و$#،ifو-f/-s/-z،exitو$?، تابع وlocal،read -p،whileوcase،>و>>و<،uniq -c،date - زنجیرهٔ
top_errorsرا مرحلهبهمرحله بدون خواندن کد توضیح میدهم - جواب ۱۱ سؤال بخش هشتم را با زبان خودم میگویم
- تغییر سؤال ۱۰ (گزینهٔ WARNING) را یک بار خودم اعمال و تست کردهام
- ارائه را با زمانسنج تمرین کردهام و زیر ۹ دقیقه تمام شد