سرورلینوکس

آموزش استفاده از AWK برای پردازش و دستکاری متن در لینوکس

مقدمه
ابزارهای لینوکس اغلب از فلسفه طراحی یونیکس پیروی می‌کنند. این ابزارها توصیه می‌شوند که کوچک باشند، برای ورودی و خروجی از فایل‌های متنی ساده استفاده کنند و به صورت ماژولار عمل نمایند. به لطف این میراث، لینوکس ابزارهای قدرتمندی برای پردازش متن مانند sed و awk را ارائه می‌دهد.

awk همزمان هم یک زبان برنامه‌نویسی است و هم یک پردازشگر متن، که این ویژگی آن را برای کار با داده‌های ساختاریافته و خط‌محور مانند لاگ‌ها، جداول و فایل‌های جداشده با کاراکترهای خاص بسیار مفید می‌سازد. در این راهنما، شما با سینتکس پایه الگو و اقدام (pattern-and-action) شروع می‌کنید، یاد می‌گیرید که در مقایسه با sed برای پردازش متن در چه مواردی بهتر عمل می‌کند، و سپس به فیلتر کردن مبتنی بر فیلد، متغیرهای داخلی و خروجی قالب‌بندی‌شده می‌رسید.

سپس، از آرایه‌های انجمنی (Associative Arrays) برای شمارش، گروه‌بندی و تجمیع مقادیر در یک گذر استفاده خواهید کرد، awk را با سایر دستورات در پایپ‌لاین‌ها ترکیب می‌کنید و آن را در اسکریپت‌های شل برای اتوماسیون تکرارپذیر جاسازی می‌کنید. همچنین با مثال‌های واقعی پارس کردن لاگ‌ها آشنا شده و در پایان با سوالات متداول پاسخ خواهید داد.

نکات کلیدی:

  • از مدل «الگو و اقدام» در awk استفاده کنید تا خطوط مورد نظر خود را مطابقت دهید و فقط آن رکوردها را تبدیل کنید.
  • ورودی را به طور پیش‌فرض به عنوان ستون‌ها در نظر بگیرید: برای فیلدها از $1, $2 و غیره استفاده کنید، و زمانی که به کل رکورد برای چاپ یا تطبیق بیشتر نیاز دارید از $0 استفاده نمایید.
  • متغیرهای FS/OFS را از پیش تنظیم کنید تا ورودی‌های جداشده (مانند /etc/passwd یا داده‌های CSV) بتوانند به طور یکپارچه پارس و چاپ شوند.
  • از BEGIN برای راه‌اندازی‌های یک‌باره (مانند تنظیم جداکننده‌ها یا چاپ هدرها) و از END برای خروجی خلاصه (مانند مجموع‌ها یا گزارش‌ها) استفاده کنید.
  • برای نوشتن منطق آگاه از رکورد، دیباگ ورودی‌های غیرمنتظره و مدیریت تمیز چندین فایل، به NR, NF, FILENAME و FNR تکیه کنید.
  • زمانی که به شمارش سریع، گروه‌بندی، جمع زدن یا تجمیع یک‌مرحله‌ای بدون نیاز به مرحله جداگانه sort/uniq نیاز دارید، از آرایه‌های انجمنی استفاده کنید.
  • هنگام پاس دادن مقادیر شل به awk از گزینه -v استفاده کنید تا نقل‌قول‌ها، فاصله‌ها و کاراکترهای خاص برنامه شما را خراب نکنند.
  • برای متن‌های جریانی و خط‌محور و گزارش‌های سریع از awk استفاده کنید، اما وقتی قوانین پارس کردن پیچیده می‌شوند (مثلاً CSV با کاماهای داخل نقل‌قول) ابزار را تغییر دهید.

AWK در برابر sed: کدام را و چه زمانی استفاده کنیم؟

هر دو ابزار awk و sed ابزارهای استاندارد پردازش متن در یونیکس هستند که اغلب با هم ذکر می‌شوند زیرا روی جریان‌های متنی (Text Streams) عمل می‌کنند. با این حال، آن‌ها با اهداف متفاوتی طراحی شده‌اند و انتخاب ابزار مناسب به نوع وظیفه‌ای که می‌خواهید انجام دهید بستگی دارد.

به طور خلاصه، sed یک ویرایشگر جریانی (Stream Editor) است که در تبدیل‌های ساده و خط‌محور تخصص دارد، در حالی که awk یک زبان اسکن الگو و پردازش داده است که برای کار با داده‌های ساختاریافته یا ستون‌محور مناسب‌تر است.

ویژگیawksed
هدف اصلیاسکن الگو و پردازش دادهویرایش جریانی و تبدیل متن
نحوه مدیریت دادهمبتنی بر فیلد و ستونمبتنی بر خط
قابلیت برنامه‌نویسیزبان اسکریپت‌نویسی کامل (متغیرها، حلقه‌ها، آرایه‌ها)اسکریپت‌نویسی محدود (دستورات پایه)
مناسب برایداده‌های ساختاریافته (CSV، لاگ‌ها، جداول)جایگزینی‌ها و ویرایش‌های ساده
خوانایی در کارهای پیچیدهبالاترپایین‌تر

چه زمانی از sed استفاده کنیم؟
زمانی که وظیفه شما شامل تبدیل‌های سرراستی است که روی خطوط متن اعمال می‌شود. به عنوان مثال، اگر می‌خواهید تمام کلمات “error” را در یک فایل با “warning” جایگزین کنید:

sed 's/error/warning/g' file.txt

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

awk '{print $1, $3}' file.txt

سینتکس پایه

دستور awk به طور پیش‌فرض در تمام سیستم‌های مدرن لینوکس نصب است. این ابزار زمانی بیشترین کاربرد را دارد که با فایل‌های متنی که به صورت قابل پیش‌بینی قالب‌بندی شده‌اند سر و کار دارید (مانند داده‌های جدولی). awk خط به خط عمل کرده و کل فایل را پیمایش می‌کند.

فرمت پایه دستور awk به شکل زیر است:

awk '/search_pattern/ { action_to_take_on_matches; another_action; }' file_to_parse

شما می‌توانید بخش «الگو» (search) یا «اقدام» (action) را حذف کنید. اگر بخش اقدام نوشته نشود، اقدام پیش‌فرض print (چاپ تمام خطوط مطابق) است. اگر بخش الگو نوشته نشود، awk اقدام تعیین شده را روی هر خط اعمال می‌کند.

یک فایل به نام favorite_food.txt ایجاد کنید:

echo "carrot sandy
wasabi luke
sandwich brian
salad ryan
spaghetti jessica" > favorite_food.txt

برای چاپ کل فایل:

awk '{print}' favorite_food.txt

برای جستجو و فیلتر کردن خطوطی که حاوی کلمه “sand” هستند:

awk '/sand/' favorite_food.txt

خروجی:

carrot sandy
sandwich brian

با استفاده از عبارات باقاعده (Regex) می‌توانید بخش‌های خاصی را هدف قرار دهید. مثلاً خطوطی که با “sand” شروع می‌شوند:

awk '/^sand/' favorite_food.txt

برای چاپ فقط ستون اولِ خطوطی که با “sand” شروع می‌شوند:

awk '/^sand/ {print $1;}' favorite_food.txt

خروجی: sandwich

شما می‌توانید به هر ستون (که با فاصله جدا شده) توسط متغیری مربوط به شماره ستون ارجاع دهید. ستون اول $1، ستون دوم $2 است و برای ارجاع به کل خط می‌توانید از $0 استفاده کنید.


متغیرهای داخلی و فرمت بسط‌یافته

دستور awk از چندین متغیر داخلی برای اختصاص اطلاعات در حین پردازش فایل استفاده می‌کند:

  • FILENAME: نام فایل ورودی فعلی.
  • FNR: شماره رکورد فعلی نسبت به فایل ورودی فعلی.
  • FS: جداکننده فیلد (Field Separator). به طور پیش‌فرض فاصله (Whitespace) است.
  • NF: تعداد فیلدهای رکورد (خط) فعلی.
  • NR: شماره رکورد (خط) فعلی در کل.
  • OFS: جداکننده فیلد برای خروجی. پیش‌فرض فاصله است.
  • ORS: جداکننده رکورد برای خروجی. پیش‌فرض خط جدید (Newline) است.
  • RS: جداکننده رکورد در فایل ورودی. پیش‌فرض خط جدید است.

برای مثال، برای چاپ هر خط همراه با شماره خط:

awk '{print NR, $0}' file.txt

سینتکس awk شامل بلوک‌های اختیاری BEGIN و END نیز می‌شود. این بلوک‌ها قبل و بعد از پردازش فایل اجرا می‌شوند:

awk 'BEGIN { action; }
/search/ { action; }
END { action; }' input_file

به عنوان مثال، فایل /etc/passwd با دو نقطه (:) جدا می‌شود. برای چاپ ستون اول این فایل:

awk 'BEGIN { FS=":"; }
{ print $1; }' /etc/passwd

جستجوی فیلد و عبارات ترکیبی

برای جستجوی یک الگو در فیلد خاص (به جای کل خط)، می‌توانید از عملگر ~ استفاده کنید.

فایل favorite_food.txt را با افزودن شماره آیتم به روزرسانی کنید:

echo "1 carrot sandy
2 wasabi luke
3 sandwich brian
4 salad ryan
5 spaghetti jessica" > favorite_food.txt

برای پیدا کردن غذاهایی که در ستون دوم با “sa” شروع می‌شوند:

awk '$2 ~ /^sa/' favorite_food.txt

خروجی:

3 sandwich brian
4 salad ryan

برای پیدا کردن خطوطی که غذایشان با “sa” شروع نمی‌شود (با اضافه کردن ! قبل از ~):

awk '$2 !~ /^sa/' favorite_food.txt

شما می‌توانید شرایط را با هم ترکیب کنید. مثلاً خطوطی که غذا با “sa” شروع نمی‌شود و شماره آن‌ها کمتر از 5 است:

awk '$2 !~ /^sa/ && $1 < 5' favorite_food.txt

استفاده از آرایه‌های انجمنی برای تجمیع داده‌ها

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

شمارش رخدادها
فایلی به نام fruits.txt ایجاد کنید:

echo "apple
banana
apple
orange
banana
apple" > fruits.txt

برای شمارش تعداد تکرار هر میوه:

awk '{count[$1]++} END {for (item in count) print item, count[item]}' fruits.txt

در این مثال، count[$1]++ یک شمارنده برای هر مقدار در ستون اول افزایش می‌دهد و در بلوک END نتایج چاپ می‌شوند.

جمع زدن مقادیر
فایل sales.txt:

echo "Alice 100
Bob 200
Alice 150
Bob 50" > sales.txt

برای محاسبه مجموع فروش هر شخص:

awk '{sum[$1] += $2} END {for (name in sum) print name, sum[name]}' sales.txt

پردازش خروجی برنامه‌های دیگر

شما می‌توانید به جای فایل، خروجی سایر برنامه‌ها را به awk پایپ (Pipe) کنید. مثلاً استخراج آدرس IPv4 از دستور ip:

ip a s eth0 | awk -F '[\/ ]+' '/inet / {print $3}'

در اینجا فلگ -F به awk می‌گوید که فیلدها را با اسلاش (/) یا فاصله جدا کند. عبارت inet / خطوط دارای IP را پیدا کرده و $3 آدرس IP را چاپ می‌کند.


استفاده از AWK در اسکریپت‌های شل و اتوماسیون

شما می‌توانید دستورات awk را مستقیماً درون اسکریپت‌های Bash قرار دهید.
مثال:

#!/bin/bash

threshold=100

# متغیر شل به awk پاس داده می‌شود
awk -v limit="$threshold" '$2 > limit {print $1, $2}' sales.txt

در این اسکریپت، متغیر threshold از بش به awk با استفاده از فلگ -v پاس داده می‌شود تا فقط رکوردهایی که فروش آن‌ها بیشتر از 100 است چاپ شوند.

همچنین می‌توانید روی چندین فایل حلقه بزنید:

#!/bin/bash

for file in *.log; do
    echo "Processing $file"
    awk '/ERROR/ {print $0}' "$file"
done

مثال‌های واقعی: پارس کردن لاگ و استخراج داده

پارس کردن لاگ دسترسی آپاچی (Apache Access Logs)
در لاگ‌های آپاچی، IP کلاینت در فیلد اول ($1) و کد وضعیت HTTP در فیلد نهم ($9) قرار دارد.

awk '{print $1, $9}' access.log

برای شمارش خطاهای 404:

awk '$9 == 404 {count++} END {print "404 errors:", count+0}' access.log

(عبارت count+0 تضمین می‌کند که اگر خطایی پیدا نشد، عدد 0 چاپ شود).

استخراج داده از فایل‌های CSV
با تغییر جداکننده، awk به راحتی فایل‌های CSV را مدیریت می‌کند:

awk -F ',' '{print $1, $3}' data.csv

این دستور نام و شهر (ستون اول و سوم) را از فایل CSV چاپ می‌کند.

تحلیل فایل‌های سیستمی
برای لیست کردن کاربرانی که UID آن‌ها بیشتر از 1000 است:

awk -F ':' '$3 > 1000 {print $1, $3}' /etc/passwd

سوالات متداول (FAQ)

۱. تفاوت AWK، gawk و mawk چیست؟
awk رابط زبان و دستور تعریف شده در استاندارد POSIX است. gawk (GNU Awk) پیاده‌سازی پیش‌فرض در بسیاری از توزیع‌های لینوکسی است و شامل ویژگی‌های اضافه‌تری نسبت به POSIX است. mawk پیاده‌سازی دیگری است که بر سرعت و مصرف کم منابع تمرکز دارد.

۲. چگونه جداکننده فیلد (Field Separator) سفارشی را در AWK مشخص کنم؟
می‌توانید با فلگ -F این کار را انجام دهید. مثلاً awk -F':' '{print $1}' /etc/passwd از دو نقطه به عنوان جداکننده استفاده کرده و فیلد اول را چاپ می‌کند.

۳. چگونه می‌توانم یک متغیر شل را به دستور AWK پاس بدهم؟
برای این کار از گزینه -v استفاده کنید. مثلاً: threshold=100; awk -v t="$threshold" '$3 > t {print $0}' file.txt.

۴. آیا AWK برای پردازش فایل‌های بزرگ مناسب است؟
بله. awk ورودی را یک رکورد در هر زمان پردازش می‌کند و نیازی به بارگذاری کل فایل در حافظه ندارد، که این امر آن را برای مجموعه‌داده‌های بزرگ کارآمد می‌سازد.


نتیجه‌گیری

تا اینجای کار، شما باید درک پایه‌ای از نحوه استفاده از دستور awk برای فیلتر کردن، قالب‌بندی و چاپ انتخابی متن از فایل‌ها و خروجی دستورات پیدا کرده باشید. همچنین دیدید که چگونه awk با استفاده از متغیرهای داخلی و بلوک‌های BEGIN/END، آرایه‌های انجمنی و الگوهای اسکریپت‌نویسی شل از یک چاپگر ساده فراتر می‌رود. با اعمال این تکنیک‌ها روی داده‌های واقعی مانند لاگ‌ها و فایل‌های جداشده، می‌توانید ابزار مناسب (awk یا sed) را بر اساس خط‌محور یا ستون‌محور بودن داده‌های خود انتخاب کنید.

نوشته های مشابه

دیدگاهتان را بنویسید

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

دکمه بازگشت به بالا