grep, sed ও awk: লিনাক্স টার্মিনালে টেক্সট প্রসেসিংয়ের উদাহরণ
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 — লিনাক্সের টেক্সট প্রসেসিংয়ের তিনটি ক্লাসিক টুল। 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 রেগুলার এক্সপ্রেশন বন্ধ করে এবং স্ট্রিংটি হুবহু খোঁজে — প্যাটার্নে বিন্দু, ব্র্যাকেট বা তারকা থাকলে এটি সুবিধাজনক।
মিলে যাওয়া লাইনের আশেপাশের প্রসঙ্গ
লগের একটি ত্রুটি প্রায়ই একটি লাইন দেখে বোঝা যায় না — তার আগের বা পরের লাইন, অথবা যে কোয়েরিটি সেটি ঘটিয়েছে, সেটিও দরকার। এর জন্য প্রসঙ্গের ফ্ল্যাগ আছে:
# মিলের পরের 3 লাইন (After)
grep -A 3 "Traceback" app.log
# মিলের আগের 2 লাইন (Before)
grep -B 2 "OOM" /var/log/kern.log
# দুই দিকে 5 লাইন করে (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) | 1 বা তার বেশিবার | 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
সব grep বিল্ডে -P থাকে না (উদাহরণস্বরূপ macOS-এর BSD grep-এ নেই), তাই পোর্টেবল স্ক্রিপ্টে 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" আছে, শুধু সেখানে 80 বদলে 8080
sed '/listen/s/80/8080/' nginx.conf
# মিলের পরে একটি লাইন যোগ করা (GNU sed)
sed '/^\[mysqld\]/a max_connections = 500' my.cnf
ব্যাকরেফারেন্স ও &
প্যাটার্নের বন্ধনীতে থাকা অংশ প্রতিস্থাপনে \1, \2 দিয়ে ফেরত আনা যায়, আর চিহ্ন & মানে পুরো মিলে যাওয়া টেক্সট।
# নাম ও পদবির জায়গা বদলানো (-E দিয়ে ERE)
$ echo "রহিম করিম" | sed -E 's/(\S+) (\S+)/\2 \1/'
করিম রহিম
# সব সংখ্যাকে বর্গাকার বন্ধনীতে মোড়ানো
$ 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 — পুরো লাইন।
# nginx লগের IP-ঠিকানা (প্রথম কলাম)
awk '{print $1}' /var/log/nginx/access.log
# /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 ফরম্যাটে 9-ম ফিল্ড)
awk '$9 >= 500' access.log
# 6-ষ্ঠ কলাম রেগুলার এক্সপ্রেশনের সঙ্গে মেলে এমন লাইন
awk '$6 ~ /POST/' access.log
# ls -l আউটপুট থেকে 100 MB-এর বড় ফাইল
ls -l | awk '$5 > 100*1024*1024 {print $9}'
BEGIN, END ও NR: awk একটি ছোট প্রোগ্রামের মতো
BEGIN ব্লক প্রথম লাইন পড়ার আগে চলে, END — শেষ লাইনের পরে। NR বর্তমান লাইন নম্বর রাখে, আর END ব্লকে এটি মোট লাইন সংখ্যা হয়ে যায়।
# রেসপন্সের আকারের যোগফল (10-ম ফিল্ড) মেগাবাইটে
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 একসঙ্গে
আসল শক্তি আছে সংমিশ্রণে। প্রতিটি টুল নিজের অংশটুকু করে, আর | ফলাফল পরের ধাপে পাঠায়।
5xx ত্রুটির সবচেয়ে বেশি IP-র তালিকা (শীর্ষ 10)
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 query-স্ট্রিং কেটে দেয়, যাতে /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}"-এ shell awk চালানোর আগেই নিজের$1ভেরিয়েবল বসিয়ে দেয়। awk-এর প্রোগ্রাম ও sed-এর এক্সপ্রেশন সিঙ্গল কোটে লিখুন। - sed-এ
gভুলে যাওয়া। এটি ছাড়া লাইনে শুধু প্রথম মিলটি বদলায়, বাকিগুলো থেকে যায়। - যাচাই ছাড়া
sed -i। ভুল রেগুলার এক্সপ্রেশন নীরবে ফাইল নষ্ট করে দিতে পারে। আগে-iছাড়া চালান, অথবা-i.bakব্যবহার করুন। - grep-এ
+ও|কাজ করে না। এগুলো বর্ধিত সিনট্যাক্স:grep -E(বাsed -E) লাগবে। - প্যাটার্নে বিন্দু।
grep 192.168.1.1192x168y1z1-ও খুঁজে পাবে, কারণ বিন্দু মানে “যেকোনো অক্ষর”।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 ব্লক। এই ইটগুলো দিয়েই প্রায় যেকোনো লগ বিশ্লেষণ গড়ে ওঠে। এই grep, sed, awk উদাহরণগুলো find, jq ও curl-এর সঙ্গে লিনাক্স কোর্সের টেক্সট প্রসেসিং নিয়ে লেকচারে হাতে-কলমে দেখানো হয়েছে।
সাধারণ প্রশ্ন
grep ও egrep-এর পার্থক্য কী?
egrep হলো grep -E-এর পুরনো উপনাম (এক্সটেন্ডেড রেগুলার এক্সপ্রেশন)। আধুনিক GNU grep egrep ডাকলে সতর্কবার্তা দেয়, তাই grep -E লিখুন।
লিনাক্সে কোনো ডিরেক্টরির সব ফাইলের ভেতর টেক্সট কীভাবে খুঁজবেন?
grep -rn "টেক্সট" /পথ ব্যবহার করুন: -r রিকার্সিভলি খোঁজে, -n লাইন নম্বর দেখায়। ফাইলের ধরন সীমিত করতে যোগ করুন --include="*.php"।
একসঙ্গে অনেক ফাইলের টেক্সট কীভাবে বদলাবেন?
খোঁজা ও sed জুড়ে দিন: grep -rl "old" . | xargs sed -i 's/old/new/g'। আগে কমিট বা ব্যাকআপ নিয়ে রাখা ভালো।
awk-এ কয়েকটি কলাম ট্যাব দিয়ে কীভাবে প্রিন্ট করবেন?
আউটপুট বিভাজক সেট করুন: awk -v OFS='\t' '{print $1, $3}' file। OFS না দিলে ফিল্ডগুলো স্পেস দিয়ে আলাদা হয়।
sed দিয়ে লাইনের শেষের স্পেস কীভাবে মুছবেন?
sed -i 's/[[:space:]]*$//' file কমান্ড ফাইলের সব লাইনের শেষের স্পেস ও ট্যাব মুছে দেয়।
“Linux: с нуля до уверенного администрирования” কোর্সে বিষয়টি অনুশীলনসহ বিস্তারিত শেখানো হয়েছে।
কোর্সে যান