فصل ۲۰ – پردازش متن

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

در این فصل خواهیم دید چگونه می‌توان جریان‌های داده را با فیلترهای گوناگون تغییر داد و اطلاعات مورد نیاز را به دست آورد.

مباحث اصلی عبارت‌اند از:


انتخاب ستون‌ها با cut

دستور cut برای استخراج بخش‌هایی از هر خط به کار می‌رود.
به کمک گزینهٔ -f می‌توان ستون‌ها را براساس جداکنندهٔ مشخص استخراج کرد.
برای نمونه اگر فایل sales.csv شامل مقادیر جداشده با کاما باشد، می‌توان ستون دوم و چهارم را این‌گونه برداشت:

cut -d',' -f2,4 sales.csv

با -c می‌توان محدودهٔ کاراکتری تعیین کرد و با --complement ستون‌های به جز موارد خواسته‌شده را گرفت.

چسباندن ستون‌ها با paste

اگر بخواهیم فایل‌هایی را به صورت ستون‌به‌ستون کنار هم قرار دهیم، paste مفید است.
مثلاً دو فایل names و phones را ترکیب کنیم:

paste names phones

به طور پیش‌فرض از تب به عنوان جداکننده استفاده می‌کند؛ با گزینهٔ -d می‌توان جداکنندهٔ دیگری تعیین کرد.

join برای داده‌های جدولی

join شبیه عملیات «پیوستن» در پایگاه‌های داده است و سطرهایی را که کلید مشترک دارند ادغام می‌کند.
پیش از استفاده باید فایل‌ها براساس ستون کلید مرتب شده باشند.
نمونه:

join -t',' -1 1 -2 1 customers.csv orders.csv

گزینهٔ -1 و -2 شمارهٔ ستون کلید را مشخص می‌کند و -t جداکننده را تعیین می‌کند.


مرتب‌سازی و حذف تکرار

دستور sort خطوط را مرتب می‌کند.
می‌توانیم نوع مرتب‌سازی را با گزینه‌های مختلف تعیین کنیم:

مثال:

sort -t',' -k3,3n -k1,1 sales.csv

این فرمان ابتدا براساس ستون سوم به صورت عددی و سپس ستون اول به شکل الفبایی مرتب می‌کند.

برای حذف خطوط تکراری پس از مرتب‌سازی از uniq استفاده می‌شود:

sort names.txt | uniq

گزینهٔ -c در uniq تعداد تکرار هر خط را نشان می‌دهد و -d فقط خطوطی را چاپ می‌کند که بیشتر از یک بار دیده شده‌اند.

همچنین comm سه فایل خروجی تولید می‌کند که اشتراک و اختلاف دو فایل مرتب‌شده را نمایش می‌دهد.


شمارش و شماره‌گذاری خطوط

برای شمارش همهٔ فایل‌های متنی در دایرکتوری:

wc -l *.txt

اگر بخواهیم تنها تعداد کل خطوط را بدانیم، گزینهٔ --total=only در wc مفید است.


تبدیل کاراکترها با tr

tr کاراکترها را جایگزین یا حذف می‌کند.
برای مثال تبدیل حروف کوچک به بزرگ:

tr '[:lower:]' '[:upper:]' < report.txt

یا حذف کاراکترهای غیرقابل چاپ:

tr -cd '\11\12\15\40-\176' < data.txt

گزینهٔ -s توالی‌های تکراری را فشرده می‌کند، مثلاً چند فاصلهٔ پشت سر هم را به یکی تبدیل می‌کند.


تب و فاصله

expand تب‌ها را به فاصله تبدیل و unexpand برعکس عمل می‌کند.
این ابزارها هنگام هماهنگ‌سازی قالب فایل‌های کد منبع مفید هستند.

expand -t4 source.c > source.spaces.c

تقسیم فایل‌ها با split و csplit

هنگام کار با فایل‌های بزرگ ممکن است بخواهیم آن‌ها را به بخش‌های کوچک‌تر تقسیم کنیم.
دستور split فایل را براساس اندازه یا تعداد خطوط تکه‌تکه می‌کند:

split -b 10M huge.log huge-

این فرمان فایل huge.log را به بلوک‌های ۱۰ مگابایتی با نام‌های huge-aa, huge-ab و ... تقسیم می‌کند.
با گزینهٔ -l می‌توان تعداد خطوط را مشخص کرد و با -d از شماره‌گذاری عددی استفاده نمود.

برای تقسیم براساس الگوها، csplit مناسب‌تر است. این ابزار بر اساس regex مرزهای فایل را پیدا می‌کند:

csplit report.txt '/^Chapter [0-9]+/' '{*}'

در مثال بالا هر فصل در فایل جداگانه‌ای ذخیره می‌شود. گزینهٔ '{*}' به csplit می‌گوید تا پایان فایل هر بار که الگو یافت شد این کار را تکرار کند. پس از تقسیم، می‌توانیم فایل‌های حاصل را پردازش یا آرشیو کنیم.


شکستن و ترکیب خطوط

نمونه:

fmt -w 72 letter.txt > letter_wrapped.txt

ترکیب ابزارها در خط لوله

قدرت واقعی ابزارهای پردازش متن زمانی آشکار می‌شود که آن‌ها را زنجیر کنیم.
مثلاً برای یافتن پرفروش‌ترین کالا بر اساس دادهٔ CSV:

cut -d',' -f2,5 sales.csv \
  | sort -t',' -k2,2nr \
  | head -n 10

یا برای استخراج دامنهٔ ایمیل‌ها از فایل متنی:

grep -E -o '[[:alnum:]_.+-]+@[[:alnum:].-]+' contacts.txt \
  | cut -d'@' -f2 \
  | sort \
  | uniq -c \
  | sort -nr

تمرین

برای تسلط بیشتر روی ابزارهای پردازش متن، سناریوهای روزمره را تمرین کنید:

  1. فایلی از لاگ وب بگیرید، فقط کدهای وضعیت (status code) را استخراج کنید و تعداد هر کد را بشمارید.
  2. فهرستی از کارمندان با حقوق دریافتی تهیه کنید و متوسط حقوق را حساب کنید.
  3. از join استفاده کنید تا دو فایل شامل کد محصول و موجودی انبار را ترکیب کنید و فقط محصولاتی را نمایش دهید که موجودی‌شان کمتر از حداقل تعریف‌شده است.

هرچه بیشتر این ابزارها را کنار هم قرار دهید، خلاقیت بیشتری در حل مسائل متنی پیدا می‌کنید.


مطالعهٔ بیشتر