# গ্রেপ (grep)

`grep` নিয়ে আমরা আগেও কাজ করেছি। `grep` এর পুরো অর্থ "global regular expression print"। বুঝতেই পারছেন। রেগুলার এক্সপ্রেশনই এর বিশেষত্ন। এর কাজই হলো টেক্সট ফাইল থেকে সেইসব লাইন খুঁজে বের করা যেগুলো প্যাটার্নে মিলবে। গ্রেপকে আমরা এ পর্যন্ত পাইপ এর দ্বারা ব্যবহার করেছি। গ্রেপের কমান্ডকাঠামোটি এরকম:

```
grep [options] regex [file...]
```

অর্থাৎ প্রথমে `grep` তারপর অপশনসমূহ, তারপর `regex` অর্থাৎ রেগুলার এক্সপ্রেশন এবং সবশেষে এক বা একাধিক ফাইল।

এবার দেখে নেওয়া যাক গ্রেপে ব্যবহৃত কিছু অপশন:

| অপশন | লং অপশন              | কাজ                                                                      |
| ---- | -------------------- | ------------------------------------------------------------------------ |
| -i   | --ignore-case        | বড় ও ছোটহাতের লেখার মধ্যে পার্থক্য করবে না। দুটোই গ্রহণ করবে।            |
| -v   | --invert-match       | যেসব লাইন মিলবে সেগুলো দেখানোর বদলে যেগুলো মিলবে না সেগুলো দেখাবে।       |
| -c   | --count              | লাইনগুলো না দেখিয়ে মোট কতগুলো লাইনে মিলেছে তার সংখ্যা জানাবে।            |
| -l   | --files-with-matches | মিলে যাওয়া লাইন না দেখিয়ে লাইনগুলো কোন ফাইলের তার নাম দেখাবে।            |
| -L   | --file-without-match | -l অপশনের মত তবে উল্টো। অর্থাৎ সেই ফাইলগুলোর নাম দেখাবে যেগুলোতে মেলেনি। |
| -n   | --line-number        | মিলে যাওয়া লাইনের নম্বর দেখাবে।                                          |
| -h   | --no-filename        | একাধিক ফাইলে খোঁজার সময় ফাইলের নাম দেখাবে না।                            |

এবার গ্রেপের শক্তিপরীক্ষার জন্য আমাদের কিছু ফাইল দরকার। অতএব, কিছু ফাইল তৈরী করা যাক:

```
me@howtocode-pc:~$ ls /usr/bin > dirlist-usr-bin.txt
me@howtocode-pc:~$ ls /usr/lib > dirlist-usr-lib.txt
me@howtocode-pc:~$ ls /usr/local > dirlist-local.txt
me@howtocode-pc:~$ ls /usr/share > dirlist-usr-share.txt
me@howtocode-pc:~$ ls dirlist*.txt
dirlist-usr-bin.txt  dirlist-usr-lib.txt  dirlist-usr-local.txt  dirlist-usr-share.txt
```

তো, এবার দেখা যাক আমাদের এই চারটি ফাইলে bzip কোথায় কোথায় লেখা আছে:

```
me@howtocode-pc:~$ grep bzip dirlist*.txt
dirlist-usr-bin.txt:bzip2
dirlist-usr-bin.txt:bzip2recover
dirlist-usr-lib.txt:libzip
dirlist-usr-lib.txt:libzip.so
dirlist-usr-lib.txt:libzip.so.2
dirlist-usr-lib.txt:libzip.so.2.1.0
```

আমরা দেখছি প্রত্যেকলাইনে একটি করে ফাইলের নাম এবং সেই ফাইলে bzip এর সাথে মিলে যাওয়া লাইনটি। এবার আমরা যদি চাইতাম শুধু দেখবো কোন কোন ফাইলে bzip আছে সেটা এভাবে করতে পারি:

```
me@howtocode-pc:~$ grep -l bzip dirlist*.txt
dirlist-usr-bin.txt
dirlist-usr-lib.txt
```

এবার শুধু ফাইলের নাম দেখাচ্ছে। এবার আমরা যদি দেখতে চাই কোন কোন ফাইলের মধ্যে bzip নাই, সেটা দেখতে পারি এভাবে:

```
me@howtocode-pc:~$ grep -L bzip dirlist*.txt
dirlist-usr-local.txt
dirlist-usr-share.txt
```

আমরা দেখতে পাচ্ছি কোনো দুটি ফাইলে bzip নাই।

## লিটারাল এবং মেটাক্যারেক্টার (Litarals and Metacharacter)

এপর্যন্ত আমরা খুব সাধারণ রেগুলার এক্সপ্রেশন বা রেজেক্স ব্যবহার করেছি। যার মধ্যে ছিল শুধু লিটারাল ক্যারেক্টার। লিটারাল হচ্ছে সেইসব ক্যারেক্টার যেগুলোর বিশেষ কোনো অর্থ নাই রেজেক্সে। যেমন a, b, ই, ভ ইত্যাদি। অর্থাৎ, a বলতে a-ই বুঝবে। আমাদের পূর্ববর্তী রেজেক্স ছিল bzip। যেখানে b, z, i ও p এই চারটি লিটারাল ক্যারেক্টার খুঁজতে বলেছি যাদের মধ্যে আর কোনো ক্যারেক্টার থাকবে না।

অন্যদিকে আছে কিছু মেটাক্যারেক্টার। রেজেক্সে মেটাক্যারেক্টারগুলোর বিশেষ অর্থ আছে। আমরা যেমন ওয়াইল্ডকার্ডের জন্য \* ও ? ব্যবহার করেছি সেরকম। গ্রেপ এই মেটা ক্যারেক্টারগুলো ব্যবহার করে:

^ $ . \[ ] { } ( ) - ? \* + | \\

এগুলো ছাড়া বাকি সব ক্যারেক্টার লিটারাল।

**মনে রাখা প্রয়োজন যে এইসব ক্যারেক্টারের শেলের কাছেও বিশেষ অর্থ আছে। তাই সম্পূর্ণ রেজেক্সকে '' চিহ্ন দিয়ে ক্যোট করে দেওয়া ভালো যেন শেল এগুলোকে এক্সপ্যান্ড করার চেষ্টা না করে।**

## এনি ক্যারেক্টার (Any Character)

আমরা যদি রেজেক্সে ডট(ফুলস্টপ) চিহ্ন ব্যবহার করি তাহলে ডটের স্থানে যেকোনো ক্যারেক্টার ম্যাচ করবে। একটা উদাহরণ দেখা যাক:

```
me@howtocode-pc:~$ grep -h '.zip' dirlist*.txt
bunzip2
bzip2
bzip2recover
funzip
gpg-zip
gunzip
gzip
hunzip
hzip
lrunzip
lrzip
preunzip
prezip
prezip-bin
unzip
unzipsfx
liblrzip.so
liblrzip.so.0
liblrzip.so.0.0.0
libzip
libzip.so
libzip.so.2
libzip.so.2.1.0
p7zip
```

আমাদের রেজেক্স ছিল `.zip` অর্থাৎ zip এর আগে অন্তত একটি যেকোনো ক্যারেক্টার থাকতে হবে। এজন্যই, হয়ত আপনি লক্ষ্য করেছেন ফলাফলে `zip` নেই। কারন `zip` এর আগে কোনো ক্যারেক্টার নেই।

## এ্যাঙ্কর (Anchor)

রেজেক্সে দুটি এ্যাঙ্কর মেটাক্যারেক্টার আছে। '^' (ক্যারেট) এবং '$' (ডলার) চিহ্ন। প্রথমটি রেজেক্সের শুরুতে ও দ্বিতীয়টি শেষে বসে। প্রথমটি শুধু সেইসব ম্যাচ বের করে যেগুলোর শুরুতে রেজেক্সটি আছে। দ্বিতীয়টি খুঁজে বের করে যেগুলোর শেষে থাকে। আসুন, ব্যবহার করে দেখি:

```
me@howtocode-pc:~$ grep -h '^zip' dirlist*.txt
zip
zipcloak
zipcmp
zipgrep
zipinfo
zipmerge
zipnote
zipsplit
ziptorrent
me@howtocode-pc:~$ grep -h 'zip$' dirlist*.txt
funzip
gpg-zip
gunzip
gzip
hunzip
hzip
lrunzip
lrzip
preunzip
prezip
unzip
zip
libzip
p7zip
me@howtocode-pc:~$ grep -h '^zip$' dirlist*.txt
zip
```

প্রথমে আমরা সেইসব ম্যাচ খুঁজলাম যার শুরুতে zip আছে এবং পরবর্তীতে খুঁজলাম কোনগুলোর শেষে আছে। সবার শেষে দেখলাম কোনগুলোর শুরু এবং শেষে `zip` আছে। স্বাভাবিকভাবেই `zip` ছাড়া আর কোনো ম্যাচ ছিল না।
