گاهی اوقات جستوجو در داخل فایلهای مختلف که حجم بالایی دارند و یا دادههای مختلفی در آنان ذخیره شده است، و یا جستوجو در بین اطلاعات در سیستمعاملهای شبه یونیکس همانند گشتن دنبال سوزن در انبار کاه است. به طور کلی یافتن اطلاعات و حتی اطلاعات مهمی در بین اطلاعات غیر مفید و یا مقادیر بالایی از متون کار بسیار دشواری خواهد بود. همچنین امروزه به طور گسترده دادهها در حال بزرگتر شدن هستند و بزرگدادهها این روزها در موارد مختلفی برای نگاهداری و ثبت اطلاعات استفاده میشوند. برای آنکه بتوان در این اطلاعات زیاد به دنبال اطلاعات باشید باید از ابزارهای خاصی استفاده کنید که در این مطلب به آنان خواهیم رسید.
خوشبختانه معمولا دو حالتی که ممکن است در زمانی که به دنبال اطلاعات خاصی در فایلهای بزرگ هستید، پیشآید؛ یعنی زمانی که نمیدانید دنبال چه اطلاعاتی میگردید یا زمانی که میدانید دنبال چه نوع و چه اطلاعاتی هستید، روشهای مختلفی وجود دارد. پس بنابراین برای هر دو حالت روشی هست که به اطلاعات خود دستیابید. بنابراین استفاده از روشها و ابزارهای گفته شده برای هر یک از این حالات به خود شما بستگی دارد. اگر نمیدانید آن چیزی که دنبالش هستید دقیقا چیست و فقط مشخصات و برخی مسائل مرتبط با آن را میدانید، از گزینههای مرتبط با آن که در مقاله توضیح داده شده است استفاده کنید و اگر عبارت مورد جستوجو کاملا مشخص است نیز باید از ابزار قابل استفاده در این وضعیت، استفاده کنید.
زمانی که میدانید دنبال چه چیزی میگردید
در برخی موارد همانطور که ذکر شد کاملا میدانید دنبال چه کلماتی هستید و یا ترکیب خاصی از کلمه مثلا پنج حرف اول آن را در خاطر دارید. در این زمان به راحتی میتوانید از دستور گِرِپ «grep» استفاده کنید. در این دستور میتوان اطلاعات و کلمات خاصی را بین چندین اطلاعات جستوجو کرده و به نمایش گذاشت. این دستور در مواقعی که بخواهید خروجی بزرگی که دستور خاصی ایجاد کرده و به کلمات و موارد خاصی محدود کنید؛ نیز به کار میرود. مثلا اگر میخواهید با دستوری اطلاعات بستههای نرمافزاری نصب شده را ببینید اما به دنبال این هستید که آیا مثلاً «GCC» نصب است یا نه؟ برای این کار شما فقط کافی است که دستور مورد نظر را نوشته و خروجی را با استفاده از نویسه لوله «Pipe» به برنامه گِرِپ لولهکشی کنید. سپس اگر هر شرطی در گِرِپ به کار رفته باشد، گِرِپ خروجی را محدود خواهد کرد.
در این مثال ما از یک فایل متنی استفاده کردهایم که «poem» نام دارد که محتوای آن از یک شعر انگلیسی تشکیل شده است، این فایل یک فایل متنی عادی و ساده است که بدون پسوند txt است. در سیستمعامل یونیکس و شبهیونیکسها نیازی به نوشتن پسوند فایل نیست و نوع فایل در داخل خود فایل تعریف شده است. اینجا چون فایل به صورت متن عادی است پس به عنوان یک متن عادی در نظر گرفته میشود. با این حال استفاده از پسوند در یونیکس نیز پشتیبانی می شود، اما لازم نیست نوشته شود. برخلاف ویندوز که حتما باید پسوند فایل را مشخص کنیم.
یکی از سادهترین جستوجوها، جستوجو به دنبال کلمهای خاص است که برای انجام آن از دستور زیر استفاده میشود. دستور زیر کلمه مورد نظر را در متن جستوجو میکند و کلماتی را که همانند آن هستند و یا در این کلمات چنین کلمهای استفاده شدهاست را نمایش میدهد. مثلا اگر ما «happ» را جستوجو کنیم؛ کلمات دیگری چون «happy» و «happiness» نمایش داده خواهد شد.
ehsan@ETARCH ~ % grep happ poem
که در صورت اجرای دستور فوق برای شعر مورد نظر ما خروجی زیر در خروجی نمایش داده شده است.
To bring joy and happiness to the world Singing happy birthday and clapping theirs hands And give her a bright and happy future And I want to wish you happy birthday And thank you for the joy and happiness you've given
همچنین اگر بخواهیم دنبال کلمه خاصی بگردیم دستور فوق را با کلید «-w» همراه میکنیم. مثلا در مورد مثالی برای جستوجوی کلمه «hope»، به شکلی که دقیقا همین کلمه را برایمان پیدا کند؛ باید دستور را به شکل زیر به کار بریم.
ehsan@ETARCH ~ % grep -w hope poem :(
اگر دستور فوق را برای شعری که در فایل فوق ذخیره کردهایم، اعمال کنیم؛ خروجی فوق را مشاهده خواهیم کرد. همچنین همانطور که در دو خروجی زیر و بالا قابل مشاهده است، وقتی کلمهای در داخل متن با کلمه مورد جستوجو را بررسی کرد و کلمات با هم تطبیق داشتند؛ همان خط به طور کامل در خروجی قرار میگیرد.
You give me hope and peace of mind
مشکلات جستوجوی فارسی در ZSH در هنگام استفاده از برخی تنظیمات که خروجی را رنگی میکنند؛
با وجود در صورت استفاده از ZSH و برخی تنظیمات خاص برای رنگی کردن خط فرمان، این جستوجو در داخل فایلهایی که در آنان کلمات فارسی وجود دارد؛ با کمی مشکل همراه خواهد بود. مثلا اگر در شعر فارسی همین دستور را به کار گیرید؛ خروجی به صورت منظم نبوده و به جای چینش از سمت راست. هر کلمه نوشته شده و سپس کلمه بعدی آن از سمت چپ چینش میشود. حتی برخی کلمات درست نوشته شده و برخی نامرتب نوشته شده که باعث گیجی میشود. به عنوان مثال دستور زیر را نوشتهایم تا در شعر زیبای موش و گربه عبید زاکانی به جستوجوی کلمه موش بگردیم.
ehsan@ETARCH ~ % grep -w موش persain-poem
خروجی آن کاملا آشفته و عجیب مینماید! با این حال موفق به یافتن کلمات درست شده است. در صورت مشاهده خروجی به شکل نامرتب، نگرانی به خود راه ندهید. اگر خروجی را از ترمینال رونویسی کرده کرده و در یک ویرایشگر متنی ساده مثل GEdit درج کنید، تمامی حروف در جای صحیح قرار خواهند گرفت.
بیا بشنو حدیث گربه و موش قصهٔ موش و گربه برخوانا قصهٔ موش و گربهٔ منظوم ناگهان جست و موش را بگرفت موش گفتا که من غلام توام ندرم موش را بدندانا هفت موش گزیده برجستند پنج موش گزیده را بگرفت آندو موش دگر که جان بردند پنج موش رئیس را بدرید گربه گفتا که موش گه خورده آنقدر موش و گربه کشته شدند غرض از موش و گربه برخواندن
همانطور که قابل مشاهده است؛ حتی اگر خروجی را دی محیطی مانند اینجا نیز درج شود، خروجی کاملا مرتب و خوانا است. شکل زیر نشاندهنده حالت خروجی در ترمینال خواهد بود. مشکل اصلی زمانی است که میخواهد کلمه موش را به رنگ قرمز و به صورت ضخیم مشخص کند که شاید همین مورد خروجی را از نظم خارج کرده است.
پیدا کردن اگوها در برخی موارد ممکن است به کاربرد ترفندهایی خاص نیاز داشته باشد. به عنوان مثال اگر بخواهیم در شکل بالا به دنبال کلمهای خاص بگردید، تنها کلماتی نمایش داده میشوند که بزرگی و کوچکی آنها یکسان با کلمه مورد نظر برای جستوجو باشد. مثلا اگر من کلمه «bird» را در شعر فوق جستوجو کنم؛ خروجی خاصی مشاهده نخواهم کرد. به دلیل آنکه در متن چنین کلمهای را نیافته است.
ehsan@ETARCH ~ % grep bird poem
اما اگر همان کلمه را با حروف بزرگ بنویسم؛ خروجی مشابه زیر خواهد بود. به طور کلی دستور فوق به بزرگی و کوچکی حروف حساس است.
Singing Birds flying on the tree tops
برای از بین بردن حساسیت به بزرگی و کوچکی حروف در دستور grep، باید دستور فوق را به شکل زیر تغییر دهیم. دستور زیر فقط در Bash قابل اجرا است و در ZSH با خطا مواجه میشود.
[ehsan@ETARCH ~]$ grep [Bb]ird poem
اگر بخواهیم دنبال جملاتی بگردیم که با کلمهای خاص شروع شدهاند میتوانید از دستور به شکل زیر استفاده کنید. یعنی قل از کلمه یک هشتک «^» بنویسید.
[ehsan@ETARCH ~]$ grep ^And poem
خروجی دستور فوق به شکل زیر خواهد بود. که همگی جملات با «And» شروع شدهاند.
And seashells washes up on the sand And on a hospital bed in the city of Novi Sad And to the park to run and play And the little girl become a young woman And today family and friends celebrates her birthday And she blows out the candles and make a wish And smiles with her beautiful green eyes And as the music and sounds fills her home And giving one of her amazing lovely laugh And every day mom and dad thank god for her And they prayer for god to bless her And give her a bright and happy future And I would never forget that special day And under the shades of your friendship And you hold a piece of me that And you're hold in the highest esteem And I want to wish you happy birthday And thank you for the joy and happiness you've given
اگر در شعر فارسی عبید زاکانی نیز به دنبال این هستیم که جملاتی که در اول آنان «گربه» است را بیابیم؛ باید از دستور مشابه استفاده کنیم.
[ehsan@ETARCH ~]$ grep ^گربه persain-poem
تمامی خطوطی که در شعر موش و گربه با کلمه «گربه» آغاز شدهاند از قرار زیر هستند.
گربه در پیش من چو سگ باشد گربه این را شنید و دم نزدی گربه گفتا دروغ کمتر گوی گربه آنموش را بکشت و بخورد گربه چون موشکان بدید بخواند گربه با چنگها و دندانا گربه کرده است ظلم بر ماها گربه گفتا که موش گه خورده گربههای براق شیر شکار گربه شد سرنگون ز زینانا گربه را هر دو دست بسته بهم گربه چون دید شاه موشانرا
اگر بخواهیم جملاتی را که در آخر آنان کلمه مورد جستوجو وجود دارد را در خروجی نمایش دهد؛ باید بعد از کلمه یک علامت دلار «$» قرار دهیم؛ مثلا در جستوجو برای جملات پایان یافته با «وش» دستور زیر را اجرا میکنیم.
[ehsan@ETARCH ~]$ grep وش$ persain-poem
مصراع یا خطوطی که با کلمه «وش» تمام شدهاند دو خط اول یعنی خطوط زیر هستند.
گر داری تو عقل و دانش و هوش بیا بشنو حدیث گربه و موش
اگر میخواهید جملاتی را که با حروف صدادار خاصی هستند را برایمان مشخص کند، میتوانیم از دستور زیر استفاده کرد.
[ehsan@ETARCH ~]$ grep -E "[AEIOUaeiou]{2}" poem | head -3
در دستور بالا تمامی جملاتی که از حروف صدادار مشخص شده بهرهمند هستند را به خروجی دستور «head» لولهکشی میکند که در آنجا سه سطر بالایی نمایش داده خواهند شد.
The sun shines beneath the blue Serbian Sky's Singing Birds flying on the tree tops And seashells washes up on the sand
دستور زیر کلماتی که با حروف صدادار AO و ao هستند را برایمان مشخص میکند.
[ehsan@ETARCH ~]$ grep -E "[AOao]{2}" poem
خروجی دستور بالا برای شعر ما به شکل زیر خواهد بود.
Flowers blooms and fruits on the trees Learning to walk taking her first foot steps Taking her to her first day in school Ice cream ,cakes food and fruit juices
برخی مواقع پیش میآید که میخواهید به دنبال رشتههایی باشید که از ۹ یا ۱۰ حرف تشکیل شدهاند.
ehsan@ETARCH ~ % grep -E "[[:alpha:]]{9,10}" poem
دستور بالا برای شعر مورد استفاده ما، خروجی زیر را تولید میکند. در برخی تنظیمات، ZSH یا BASH تمامی کلماتی که از ۹ یا ۱۰ حرف تشکیل شدهاند را به رنگ قرمز مشخص میکنند.
And seashells washes up on the sand To bring joy and happiness to the world Their beautiful precious little girl And today family and friends celebrates her birthday And smiles with her beautiful green eyes The stars are twinkling in the Sky's Every one hugging her and taking a photograph Every year her birthday are celebrated And under the shades of your friendship beautiful Serbian princess from heaven And thank you for the joy and happiness you've given
برخی مواقع نیز پیش میآید که بخواهیم کلمهای بلند با طوب بیشتر از کلمه وارد شده را که به وسیله کلمه کوچکتر دیگر ایجاد شده است را بیابیم. مثلا دنبال کلمات بلندی هستیم که در آنان کلمه «beaut» وجود داشته باشد.
[ehsan@ETARCH ~]$ grep -E "beaut[^[:space:]]+" poem
خروجی دستور فوق به شکل زیر است که در آن کلمات بلندتر مشتق شده از «beaut» مانند «beauty» و «beautiful» را در فایل مذکور پیدا کرده است.
Mothers nature majestic beauty at full sight Their beautiful precious little girl And smiles with her beautiful green eyes beautiful Serbian princess from heaven
جستوجو در شعر بالا به اشکال مختلف باعث شد تا شما با نحوه استفاده از این دستور آشنا شوید. با وجود این استفاده از این دستور بسیار کاربردی تر از پیدا کردن چندین کلمه یا جمله از یک شعر کاربرد دارد. به عنوان نمونه شما میخواهید بدانید کارت گرافیکی سیستم شما چه مشخصاتی دارد برای این کار خروجی دستور «lspci -k» را به grep لولهکشی میکنیم.
[ehsan@ETARCH ~]$ lspci -k | grep VGA
خروجی دستور بالا برای سیستمی که در حال حاضر مشغول استفاده از آن هستم، دو کارت گرافیک زیر را نمایش میدهد.
00:02.0 VGA compatible controller: Intel Corporation 3rd Gen Core processor Graphics Controller (rev 09) 01:00.0 VGA compatible controller: NVIDIA Corporation GF117M [GeForce 610M/710M/820M / GT 620M/625M/630M/720M] (rev ff)
در مثالی دیگر در فایل «pacman.log»، به دنبال اطلاعات مربوط به مثلا نصب و حذف و بهروزرسانی بستهای خاص گشت. دستور زیر تمامی اعمال مرتبط با بسته نرمافزاری DigiKam را نمایش خواهد داد.
ehsan@ETARCH ~ % grep -C 1 digikam /var/log/pacman.log
کلمه کلیدی C و سپس عدد بعد از آن مشخص میکنند تا چند خط بعد از هر نتیجه را هم نمایش دهد که در دستور بالا فقط یک خط بیشتر نمایش داده خواهد شد. توجه کنید که این خطوط بعد و قبل از نتیجه به یک اندازه اضافه میشود. یعنی اگر عدد یک را بنویسید یک خط قبل نتیجه و یک خط بعد نتیجه را نشان خواهد داد. اگر عدد دو را بنویسید نیز دو خط قبل و بعد هر نتیجه را نمایش خواهد داد تا نمای بهتری از اطلاعات داشته باشید که به نحوی میتوان گفت اطلاعات را دستهبندی نیز خواهد کرد.
[2015-06-16 20:54] [ALPM] transaction completed [2015-06-16 20:54] [PACMAN] Running 'pacman -S digikam' [2015-06-16 20:55] [PACMAN] Running 'pacman -S fontconfig-iu-comp freetype2-infinality-ultimate' -- [2015-06-16 20:59] [PACMAN] Running 'pacman --color auto -S --asdeps --needed extra/libraw' [2015-06-16 20:59] [PACMAN] Running 'pacman -S digikam' [2015-06-16 21:00] [PACMAN] Running 'pacman -S kdegraphics-ksnapshot' -- [2015-06-16 21:01] [ALPM] transaction completed [2015-06-16 21:01] [PACMAN] Running 'pacman -S digikam' [2015-06-16 21:02] [ALPM] transaction started -- [2015-06-16 21:02] [ALPM] installed libkgeomap (15.04.2-1) [2015-06-16 21:02] [ALPM] installed digikam (4.9.0-2) [2015-06-16 21:02] [ALPM] transaction completed -- [2015-06-23 18:40] [ALPM] upgraded ffmpeg (1:2.7-1 -> 1:2.7.1-1) [2015-06-23 18:40] [ALPM] upgraded digikam (4.9.0-2 -> 4.11.0-1) [2015-06-23 18:40] [ALPM] upgraded kipi-plugins (4.9.0-2 -> 4.11.0-1)
زمانی که نمیدانید، میخواهید دقیقا دنبال چه چیزی بگردید
به طور قطع و یقین اگر برنامه نویس یک زبان برنامه نویسی مانند C و حتی پایتون بوده باشید در هنگام اجرا و یا کامپایل با خطای سهوی در Syntax و نوشتارها مواجه شدهاید. معمولا این مفسرها یا مترجمهای زبان برنامه نویسی اطلاعات کمی را در اختیار میگزارند که همراه با شماره خطی است که خطا در آن رخ داده است. به عنوان نمونه من قطعه کد زیر را به زبان C نوشتهام که دارای هشدار خاصی است.
#include "stdio.h" #include "stdlib.h" #define SCALE 10000 #define ARRINIT 2000 void pi_digits(int digits) { int carry = 0; int arr[digits + 1]; for (int i = 0; i <= digits; ++i) arr[i] = ARRINIT; for (int i = digits; i > 0; i-= 14) { int sum = 0; for (int j = i; j > 0; --j) { sum = sum * j + SCALE * arr[j]; arr[j] = sum % (j * 2 - 1); sum /= j * 2 - 1; } printf("%04d", carry + sum / SCALE); carry = sum % SCALE; } } int main(int argc, char* argv) { int n = argc == 2 ? atoi(argv[1]) : 100; pi_digits(n); return 0; }
سپس کدهای بالا را در فایلی با نامی دلخواه ذخیره و دستور زیر را برای کامپایل کد اجرا میکنیم.
ehsan@ETARCH ~ % gcc pi-gen.cpp -o pi-generator.o
در این هنگام , در صورت کامپایل خط بالا هشدار و خطای زیر نمایش داده خواهد شد.
pi-gen.cpp:24:5: warning: second argument of ‘int main(int, char*)’ should be ‘char **’ [-Wmain] int main(int argc, char* argv) { ^ pi-gen.cpp: In function ‘int main(int, char*)’: pi-gen.cpp:25:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive] int n = argc == 2 ? atoi(argv[1]) : 100; ^ In file included from pi-gen.cpp:2:0: /usr/include/stdlib.h:147:12: note: initializing argument 1 of ‘int atoi(const char*)’ extern int atoi (const char *__nptr) ^
حال و با فهمیدن هشدار فوق که معمولا میتوان آن را نادیده گرفت باید آن خط را یافت. برای یافتن هشدار فوق و رفع آن از دستور زیر استفاده میکنیم.
ehsan@ETARCH ~ % sed -n 24p pi-gen.cpp
خروجی آن یک خط کد میباشد که شامل همان خط مورد نظر است که در دستور وارد کردهایم.
int main(int argc, char* argv) {
در خط بالا کاملا مشخص است که از علامت نامناسبی به جای «** char» استفاده کردهام. پس نویسه «*cahr» را به نویسه درست پیشنهادی تغییر میدهم. حال اگر خطا به شکلی بود که باید چند خط قبل و بعد از خط قبلی یا خطوط قبلی نیز نمایش داده میشد. میتوانستم از دستور زیر استفاده کنم.
ehsan@ETARCH ~ % sed -n 22,26p pi-gen.cpp
خروجی دستور بالا به شکل زیر خواهد بود که خطوط ۲۲ و ۲۳ به همراه خطوط ۲۴ تا ۲۶ را هم نمایش خواهد داد.
} int main(int argc, char* argv) { int n = argc == 2 ? atoi(argv[1]) : 100; pi_digits(n);
خطای رخ داده نیز مرتبط با همان هشدار اول است که با مشاهده خط بعدی قابل فهم خواهد بود. با این حال میتوان موارد بسیار جالتری را نیز با ابزار sed انجام دهید. مثلا در دستور زیر تمامی خطوطی که شامل حلقه for هستند را با شکل ==> مشخص کردهایم.
ehsan@ETARCH ~ % sed '/for/{b label1; {:label1 ; s/$/ <===/ ;} }' pi-gen.cpp
خروجی دستور بالا بر روی کد مذکور به شکل زیر خواهد بود.
#include "stdio.h" #include "stdlib.h" #define SCALE 10000 #define ARRINIT 2000 void pi_digits(int digits) { int carry = 0; int arr[digits + 1]; for (int i = 0; i <= digits; ++i) <=== arr[i] = ARRINIT; for (int i = digits; i > 0; i-= 14) { <=== int sum = 0; for (int j = i; j > 0; --j) { <=== sum = sum * j + SCALE * arr[j]; arr[j] = sum % (j * 2 - 1); sum /= j * 2 - 1; } printf("%04d", carry + sum / SCALE); carry = sum % SCALE; } } int main(int argc, char* argv) { int n = argc == 2 ? atoi(argv[1]) : 100; pi_digits(n); return 0; } %
همچنین برای مشخص کردن مثلا دستور printf نیز از دستور زیر استفاده میشود. که خروجی آن نیز همانند بالا خواهد بود به جز این مورد که برای هر printf آن علامت را نمایش خواهد داد. دستور فوق با اعمال حرف printf به جای for با خروجی زیر همراه است.
دستور:
ehsan@ETARCH ~ % sed '/printf/{b label1; {:label1 ; s/$/ <===/ ;} }' pi-gen.cpp
خروجی:
#include "stdio.h" #include "stdlib.h" #define SCALE 10000 #define ARRINIT 2000 void pi_digits(int digits) { int carry = 0; int arr[digits + 1]; for (int i = 0; i <= digits; ++i) arr[i] = ARRINIT; for (int i = digits; i > 0; i-= 14) { int sum = 0; for (int j = i; j > 0; --j) { sum = sum * j + SCALE * arr[j]; arr[j] = sum % (j * 2 - 1); sum /= j * 2 - 1; } printf("%04d", carry + sum / SCALE); <=== carry = sum % SCALE; } } int main(int argc, char* argv) { int n = argc == 2 ? atoi(argv[1]) : 100; pi_digits(n); return 0; } %
آری، گشتن به دنبال سوزنی در انبار کاه همواره مشکل است؛ اطلاعات نیز همچون انباری کاه در هم تنیده و پیچیده شدهاند مخصوصا در زمانی که اطلاعات شامل موارد بالا و گنگی باشد. مثلا پیدا کردن اطلاعاتی خاص از لاگ «Log» سیستم مرتبط با کاربری خاص که کاملا مشکل است. برای همین منظور است که استفاده از دستورات خظ فرمان با مولفهها و ویژگیها جالبی که دارند؛ همواره یکی از راههای جستوجو در فایلها هستند. در این مطلب به موارد ساده و ابتدایی پرداخته شد تا با دستور فوق آشنا شوید؛ پیددا کردن موارد پیچیدهتر و سختتر را نیز میتوان با دستورات فوق انجام داد که ممکن است به اشکال دیگر و با مولفههای دیگر قابل انجام باشند. بنا براین با خواندن راهنمای دستورات گفته شده از طریق دستورات زیر خواهید توانست سطح دانش خود را برای استفاده از این ابزارها بالا برید.
ehsan@ETARCH ~ % man sed OR ehsan@ETARCH ~ % man grep
در آخر اگر از سیستمعاملها شبه یونیکس استفاده میکنید این دستورات در آن سیستمعامل نیز وجود خواهند داشت و محدود به گنو/لینوکس و مک نیستند. همنین اگر گوشی هوشمند اندرویدی شما روت شده است نیز فاقد خواهید بود تا با نصب ابزار بیزیباکس «busybox» دستورات فوق را اجرا کنید.