গাইড

grep, sed ও awk: লিনাক্স টার্মিনালে টেক্সট প্রসেসিংয়ের উদাহরণ

হালনাগাদ: · Skillaria.Top

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-এর এমন উদাহরণ যেগুলো লগ, কনফিগ ও কমান্ডের আউটপুট বিশ্লেষণের সময় সত্যিই কাজে লাগে, সঙ্গে সাধারণ ভুলগুলোও।

কখন কোনটি ব্যবহার করবেন

তিনটি টুলই টেক্সট লাইন ধরে ধরে পড়ে এবং ফলাফল স্ট্যান্ডার্ড আউটপুটে লেখে, তাই | দিয়ে সহজেই একসঙ্গে জোড়া যায়। পার্থক্য হলো প্রতিটি টুল কোন কাজটি সবচেয়ে ভালো পারে।

কাজটুলউদাহরণ
টেক্সটসহ লাইন খোঁজাgrepgrep ERROR app.log
টেক্সট বদলানোsedsed 's/http:/https:/g' file
লাইন নম্বর ধরে মোছা বা দেখানোsedsed -n '10,20p' file
একটি কলাম বের করাawkawk '{print $1}' access.log
যোগফল, গড় বা গ্রুপ করে গণনাawkawk '{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.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 ব্লক। এই ইটগুলো দিয়েই প্রায় যেকোনো লগ বিশ্লেষণ গড়ে ওঠে। এই 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: с нуля до уверенного администрирования” কোর্সে বিষয়টি অনুশীলনসহ বিস্তারিত শেখানো হয়েছে।

কোর্সে যান