آموزشچگونه

آموزش خط فرمان: قسمت پنجاه و پنجم، سایر فرمان‌های پردازش متن

Print Friendly, PDF & Email

در این درس به سایر فرمان‌های پردازش متن (Text Processing)، مانند uniq و join و paste و comm و diff و patch خواهیم پرداخت.

فرمان uniq (گزارش یا حذف خطوط تکراری)

در مقایسه با فرمان sort، فرمان uniq بسیار ساده‌تر است. فرمان uniq در ظاهر وظیفه کم‌اهمیتی را انجام می‌دهد، اما درواقع این‌گونه نیست. زمانی‌که فایل مرتب شده‌ای را در اختیار دارید، فرمان uniq خطوط اضافی را حذف کرده و نتیجه را برای ارسال به خروجی استاندارد ارسال می‌کند. درواقع این کار نیز، نوعی از مرتب‌سازی است، با این تفاوت که فقط خطوط اضافی نمایش داده نمی‌شوند. فرمان uniq معمولا در کنار sort به‌کار می‌رود، تا نتایج sort را پاک‌سازی کند.

در ادامه یک فایل تمرینی، به‌صورت زیر ایجاد می‌کنیم:

به یاد داشته باشید که از Ctrl+D به‌منظور تخریب خروجی استاندارد و پایان فایل استفاده می‌کنیم. اگر که فرمان uniq را بر روی فایل اجرا کنیم، نتایج هیچ تفاوتی با نسخه اصلی فایل نخواهند کرد و کاراکترهای اضافی حذف نخواهند شد:

دلیل آن، این است که برای آن‌که فرمان uniq بتواند وظیفه خود را انجام دهد، باید در ابتدا، ورودی مرتب‌سازی شود:

دلیل آن هم این است که در فرمان uniq فقط موارد اضافی که مجاور یکدیگر هستند را حذف می‌کند. فرمان uniq دارای چندین گزینه است که در جدول زیر لیست موارد رایج نشان داده شده است:

در این‌جا می‌بینیم که فرمان uniq با به‌کار بردن گزینه –c به‌منظور گزارش تعداد موارد تکرار شده در داخل فایل متنی استفاده شده است:

فرمان cut (حذف بخش‌هایی از هر خط فایل)

فرمان cut به‌منظور استخراج بخشی از متن از یک خط و ارسال بخش استخراج شده به خروجی استاندارد، مورد استفاده قرار می‌گیرد. این فرمان قادر است که چندین آرگومان فایل یا ورودی را از استاندارد ورودی قبول کند.

اختصاص بخش‌هایی از خط برای استخراج، کمی عجیب به نظر می‌رسد که با استفاده از گزینه‌هایی که در جدول زیر انجام می‌شود:

همان‌طور که مشاهده می‌شود، شیوه‌ای که فرمان cut متن را استخراج می‌کند، روشی غیرقابل انعطاف است. بهتر است که از فرمان cut برای استخراج متن از فایل‌هایی که توسط دیگر برنامه‌ها ایجاد شده، استفاده شود تا این‌که به‌صورت مستقیم از متن‌هایی که خودمان نوشتیم، متن استخراج کنیم.

نگاهی به فایل distros.txt خواهیم انداخت تا ببینیم که آیا به اندازه کافی برای مثال‌های ما مناسب خواهد بود یا نه. در ادامه، با استفاده از فرمان cat به‌همراه گزینه –A محتویات distros.txt را می‌بینیم:

به نظر خوب است؛ هیچ فضای اضافی وجود ندارد، تنها کاراکترهای Tab بین هر فیلد، وجود دارد تا فیلدها را جدا کند. از آن‌جایی که فایل به‌جای فاصله از کاراکتر Tab استفاده می‌کند، از گزینه –f برا استخراج فیلدها استفاده خواهیم کرد:

به این دلیل که فایل distros با کاراکتر Tab جدا شده است، بهتر است که از فرمان cut به‌منظور استخراج فیلدها به‌جای استخراج کاراکترها استفاده کنیم. دلیلش هم این است که زمانی‌که یک فایل با Tab جدا شده، بعید است که هر خط دارای همان تعداد کاراکتر باشد که در نتیجه، محاسبه موقعیت کاراکترها را دشوار و یا حتی غیرممکن می‌سازد. هرچند در مثال بالا، فیلدی را استخراج می‌کنیم که احتمالا دارای اندازه داده‌ای یکسانی است، پس می‌توانیم استخراج کاراکتر را با استخراج سال از هر خط انجام دهیم:

با اجرای فرمان cut برای بار دوم بر روی لیست خود، می‌توانیم کاراکترهایی که در موقعیت کاراکتری ۷ تا ۱۰ هستند که همان فیلد سال را شامل می‌شود، استخراج کنیم.

زمانی‌که با فیلدها کار می‌کنیم ممکن است که یک جداکننده فیلد متفاوت را به‌جای کاراکتر Tab استفاده کنیم. مثال فایل passwd را به یاد بیاورید که با کاراکتر (:) از هم جدا می‌شد:

با استفاده از گزینه –d قادر هستیم که کاراکتر دونقطه را به‌عنوان جداکننده فیلد، استفاده کنیم.

فرمان paste (ادغام خطوطی از فایل‌ها)

فرمان paste مخالف فرمان cut عمل می‌کند. به‌جای این‌که ستونی از متن یک فایل را استخراج کند، یک یا چند ستون از متن را به یک فایل اضافه می‌کند. این کار را از طریق خواندن چندین فایل و ترکیب فیلدهای پیدا شده در هر فایل در یک جریان در خروجی استاندارد انجام می‌دهد. مشابه فرمان cut، فرمان paste نیز چندین آرگومان فایل را قبول می‌کند، برای نشان دادن این‌که paste چگونه عمل می‌کند، بایستی کمی فایل distros.txt را تغییر دهیم تا یک لیست تقویمی از ریلیزهای توزیع‌ها ایجاد کنیم.

از کار اخیر خودف با استفاده از sort ابتدا لیستی از توزیع‌های مرتب شده را بر اساس تاریخ ایجاد می‌کنیم و نتایج را در یک فایل با نام distros-by-date.txt ذخیره می‌کنیم:

آخرین بخش از آماده‌سازی، استخراج تاریخ‌های انتشار و ذخیره آن‌ها در فایلی با نام distros-daste.txt می‌باشد:

اکنون بخش‌هایی که نیاز داریم را فراهم نمودیم. برای کامل کردن پروسه، با استفاده از فرمان paste ستون‌های تاریخ، نام توزیع‌ها و نسخه‌ها را کنار هم قرار داده و یک لیست تقویمی ایجاد می‌کنیم. این کار به‌سادگی با استفاده از فرمان paste و آرگومان‌هایی به ترتیب مورد نظر صورت می‌پذیرد:

فرمان join (اتصال خطوط دو فایل بر روی یک فیلد رایج)

فرمان join به نحوی شبیه فرمان paste است. از این منظر که join نیز ستون‌ها را به یک فایل اضاف می‌کند، ولی این‌کار را به شیوه‌ای یگانه انجام می‌دهد. فرمان join عملیاتی است که معمولا مرتبط با پایگاه‌داده رابطه‌ای است که در آن داده از چندین جدول با یک فیلد کلید اشتراکی به یک شکل دلخواه‌تر ترکیب می‌شوند. فرمان join همان عملیات را انجام می‌دهد. داده را از چندین فایل براساس فیلد کلید اشتراکی به هم متصل می‌کند.

برای مشاهده این‌که چگونه عملیات join در یک پایگاه‌داده رابطه‌ای انجام می‌شود، یک پایگاه‌داده بسیار کوچک شامل دو جدول را فرض کنید که هر کدام از این جداول دارای یک رکورد هستند. جدول اول CUSTOMERS به‌معنای مشتریان، دارای سه فیلد است: شماره مشتری (CUSTNUM)، نام مشتری (FNAME) و نام خانوادگی مشتری (LNAME).

جدول دوم ORDERS به معنای سفارشات، شامل چهار فیلد شماره سفارش (ORDERNUM)، شماره مشتری (CUSTNUM)، کیفیت (QUAN) و ترتیب آیتم‌ها (ITEM) است:

مشاهده می‌شود که هر دو جدول دارای فیلد مشترکی با نام CUSTNUM هستند. این نکته بسیار مهم است؛ چرا که موجب ایجاد رابطه بین جداول می‌شود.

انجام یک عملیات join به ما این اجازه را می‌دهد تا فیلدها را در دو جدول با هم ترکیب کنیم تا نتایج دلخواهی مثل ارائه فاکتور، به‌دست آید.

با استفاده از مقادیر مطابق در فیلدهای CUSTNUM در هر دو جدول، یک عملیات join قادر است، لیست زیر را ایجاد نماید:

برای شرح فرمان join، نیاز است فایل‌هایی ایجاد شوند که دارای یک کلید اشتراکی باشند. بدین منظور، از فایل distros-by-date.txt استفاده خواهیم کرد. از این فایل، دو فایل جانبی ایجاد می‌کنیم. اولی حاوی تاریخ‌های انتشار (که فیلد اشتراکی ما برای این آزمون است) و نام‌های انتشار:

و دیگری شامل تاریخ‌های انتشار و شماره‌های نسخه:

اکنون دو فایل داریم که یک کلید اشتراکی (تاریخ‌های انتشار) دارند. لازم به ذکر است که برای انجام عملیات join فایل‌ها بایستی ابتدا بر اساس کلید اشتراکی مرتب شوند.

مقایسه متون (Comparing Text)

برخی اوقات، مقایسه نسخه‌های مختلف فایل‌های متنی مفید است. به‌ویژه برای مدیران سیستم و توسعه‌دهندگان نرم‌افزار، این کار بسیار مهم است. یک مدیر سیستم ممکن است برای مثال نیاز به مقایسه یک فایل پیکربندی موجود با یک فایل نسخه قبلی پیدا کند تا مشکلات سیستم را تشخیص دهد. همین‌طور یک برنامه‌نویس اغلب نیاز پیدا می‌کند تا ببیند در طول زمان چه تغییراتی را در کد برنامه اعمال کرده است. بدین منظور فرمان‌هایی به‌کار گرفته می‌شود که اولین آن‌ها فرمان comm می‌باشد که در ادامه به شرح آن می‌پردازیم:

فرمان comm (مقایسه بین دو فایل مرتب‌شده به‌صورت خط به خط)

فرمان comm دو فایل متنی را با یکدیگر مقایسه می‌کند و خطوط یگانه هر یک و خطوط مشترک را نمایش می‌دهد. به‌منظور توضیح مطلب، دو فایل متنی تقریبا یکسان با استفاده از فرمان cat ایجاد می‌کنیم:

سپس دو فایل ایجاد شده را با استفاده از فرمان comm با هم مقایسه می‌کنیم:

همان‌گونه که مشاهده می‌کنید، فرمان comm سه ستون را در خروجی ایجاد می‌کند. اولین فرمان حاوی خطوط یگانه نسبت به فایل اول در آرگومان است. ستون دوم خطوط یگانه نسبت به فایل دوم در آرگومان است. ستون سوم خطوط مشترک بین هر دو فایل می‌باشد. فرمان comm از گزینه‌های –n پشتیبانی می‌کند که به‌جای آن اعداد ۱ و ۲ و ۳  قرار می‌گیرند که این گزینه‌ها تعیین می‌کند تا چه ستون‌هایی سرکوب شوند. برای مثال اگر بخواهیم که در خروجی فقط خطوط اشتراکی را بین هر دو فایل را مشاهده کنیم، با به‌کار بردن گزینه -۱۲ ستون‌های ۱ و ۲ را از نتایج حذف می‌کنیم:

فرمان diff (مقایسه فایل‌ها به‌صورت خط به خط)

فرمان diff نیز مانند فرمان comm، به‌منظور تشخیص تفاوت‌های بین فایل‌ها مورد استفاده قرار می‌گیرند. هر چند که فرمان diff ابزاری کاملا پیچیده‌تری است و فرمت‌های خروجی زیادی را پشتیبانی می‌کند و قادر به پردازش مجموعه فایل‌های بزگ‌تر به‌صورت یک‌جا می‌باشد.

فرمان diff اغلب توسط توسه‌دهندگان نرم‌افزار به‌منظور آزمون تغییرات بین نسخه‌های مختلف کد نرم‌افزاری استفاده می‌شود. به این دلیل که این فرمان توانایی آزمون دایرکتوری‌های کد را به‌صورت بازگشتی دارد. استفاده رایجی از فرمان diff ایجاد فایل‌های diff یا Patchهایی است که توسط برنامه‌هایی مانند patch استفاده می‌شوند تا نسخه‌ای از فایل را به نسخه‌ای دیگر تبدیل کنند.

اگر که از فرمان diff برای مشاهده فایل‌های مثال آموزش‌های قبلی استفاده کنیم، استایل پیش‌فرض خروجی آن را مشاهده خواهیم کرد.

یک توضیح جزئی از تفاوت‌های بین دو فایل:

در فرمت پیش‌فرض، قبل هر گروه از تغییرات یک فرمان (که در جدول زیر لیست کاملی از آن قابل مشاهده است)، آمده که موقعیت و انواع تغییرات مورد نیاز برای تبدیل فایل اول به فایل دومی را توصیف می‌کند.

با وجود این‌که این فرمت پیش‌فرض است ولی مانند سایر فرمت‌های اختیاری به‌صورت گسترده استفاده نمی‌شود. دو مورد از دیگر فرمت‌های رایج، فرمت‌های context format و unified format هستند.

وقتی که با استفاده از فرمت context format (گزینه –c) نمایش می‌دهیم، خروجی به شکل زیر است:

خروجی با نام و فایل و برچسب زمانی آغاز می‌گردد. فایل اول با ستاره‌هایی نشانه‌گذاری شده و فایل دوم با کاراکترهای (–) نشانه‌گذاری شده است.

سپس گروهی از تغییرات را مشاهده می‌کنید، مثلا شماره پیش‌فرض که خط‌های متن را دربرگرفته است. در گروه اول *** ۱,۴ **** را مشاهده می‌کنیم که نشان‌دهنده خط یک تا خط چهار در فایل اول است. سپس — ۱,۴ —- را می‌بینیم که نشان‌دهنده خط اول تا خط چهار در فایل دوم است. در بین یک گروه خطوط با نشان‌گرهایی آغاز می‌شوند، مثلا – و + که در جدول زیر لیست شده و معنای آن شرح داده شده است:

فرمتunified  نیز مشابه فرمتcontext  بوده؛ با این تفاوت که خلاصه‌تر می‌باشد. این فرمت را با گزینه –u نمایش می‌دهیم:

آشکارترین تفاوت میان دو فرمت context و unified در حذف خطوط تکراری متن است که موجب می‌شود فرمت unified بسیار خلاصه‌تر باشد. در این مثال، برچسب‌های زمانی مانند قبل قابل مشاهده بوده و در ادامه رشته @@ -۱,۴ +۱,۴ @@ را مشاهده می‌نمایید.

این رشته نشان‌دهنده خطوطی در فایل اول و فایل دوم هستند و در ادامه آن خود خطوط نشان داده شده‌اند.

هر خطی که با یک کاراکتر آغاز شده، معنای خاصی دارد که در جدول زیر نمایش داده شده است:

فرمان patch (اعمال diff به یک فایل اصلی)

فرمان patch برای اعمال تغییرات به فایل‌های متنی صورت می‌پذیرد. این فرمان، خروجی diff را دریافت کرده و اساسا به‌منظور تبدیل فایل‌های نسخه قدیمی به فایل‌های جدید استفاده می‌شود. یک مثال مشهور را در نظر بگیرید. هسته لینوکس توسط یک تیم بزرگ از همکاران به‌صورت آزاد، توسعه یافته است که به‌صورت مداوم تغییراتی را در کد منبع ایجاد کردند.

هسته لینوکس شامل چندین میلیون خط کد می‌باشد، بنابراین تغییر ایجاد شده توسط یک شخص، بسیار کوچک خواهد بود.  پس بی‌معنا خواهد بود که هر توسعه‌دهنده پس از تغییری کوچک، کل کد ساختار هسته را ارسال کند. به‌جای این‌کار یک فایل diff ارسال می‌شود. فایل diff حاوی تغییری از نسخه قبلی به نسخه جدیدتر به‌همراه تغییرات اعمال شده است. در ادامه، دریافت‌کننده، با استفاده از فرمان patch برای اعمال تغییرات خود بر روی کد منبع استفاده می‌کند. در نتیجه استفاده از فرمان‌های diff/patch دو مزیت فوق‌العاده دارد.

فایل diff در مقایسه با کل ساختار درختی کد، بسیار کوچک است.

فایل diff به‌طور خلاصه، تغییرات اعمال شده را نشان میدهد تا باعث شود تیم بازبینی به‌سرعت آن را ارزیابی کنند.

مسلما فرمان‌های diff/patch بر روی هر فایل متنی، نه‌تنها بر روی کد منبع کار می‌کنند. این تغییرات را می‌توان به‌صورت برابر بر روی فایل‌های پیکربندی و دیگر فایل‌های متنی نیز اعمال کرد. برای فراهم آوردن یک فایل diff برای استفاده با patch توصیه می‌شود، این‌گونه کنید:

در اینجا old_file و new_file هر دو فایل‌ها یا پوشه‌هایی حاوی فایل‌ها هستند. گزینه –r بازگشت به یک دایرکتوری درختی را پشتیبانی می‌کند.

زمانی که فایل diff ایجاد شد، می‌توانیم آن را اعمال کنیم تا فایل قدیمی را به فایل جدید patch کنیم:

این کار  را با همان فایل‌های تست، آزمایش می‌کنیم:

در این مثال یک فایل diff با نام patchfile.txt ایجاد و سپس از برنامه patch برای اعمال patch استفاده کردیم.

منبع: کتاب The Linux Command Line نوشته William E. Shotts

Related Articles

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

Close