
مقدمه
ابزارهای لینوکس اغلب از فلسفه طراحی یونیکس پیروی میکنند. این ابزارها توصیه میشوند که کوچک باشند، برای ورودی و خروجی از فایلهای متنی ساده استفاده کنند و به صورت ماژولار عمل نمایند. به لطف این میراث، لینوکس ابزارهای قدرتمندی برای پردازش متن مانند 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 یک زبان اسکن الگو و پردازش داده است که برای کار با دادههای ساختاریافته یا ستونمحور مناسبتر است.
| ویژگی | awk | sed |
|---|---|---|
| هدف اصلی | اسکن الگو و پردازش داده | ویرایش جریانی و تبدیل متن |
| نحوه مدیریت داده | مبتنی بر فیلد و ستون | مبتنی بر خط |
| قابلیت برنامهنویسی | زبان اسکریپتنویسی کامل (متغیرها، حلقهها، آرایهها) | اسکریپتنویسی محدود (دستورات پایه) |
| مناسب برای | دادههای ساختاریافته (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) را بر اساس خطمحور یا ستونمحور بودن دادههای خود انتخاب کنید.




