پیوست ‎C- پیش درآمدی بر Sed و Awk

‎C.2‎-‏ Awk

Awk ‎[1]‎ یک زبان پردازش متن با قابلیت‌های فراوان و با نوشتاری یادآور زبان C است. در حالیکه دارای مجموعه گسترده‌ای از عملگرها و امکانات است، ما در اینجا فقط اندکی از آنها را پوشش می‌دهیم - آنهایی که بیش از همه در اسکریپت‌های پوسته سودمند هستند.

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

در داخل یک اسکریپت پوسته، نقل‌قول قوی و ابروهای کمانی، بلوک‌های کد awk را محصور می‌کنند.

# ‎$1‎ فیلد شماره ‎1‎ است،‏ ‎$2‎ فیلد شماره ‎2‎ است، و غیره.

echo one two | awk '{print $1}'
# one

echo one two | awk '{print $2}'
# two

# اما فیلد شماره ‎0‎ یا ‎($0)‎ چیست؟
echo one two | awk '{print $0}'
# one two
# تمام فیلدها!


awk '{print $3}' $filename
#  فیلد شماره ‎3‎ از فایل ‎$filename‎ را در ‎stdout‎ چاپ می‌کند.

awk '{print $1 $5 $6}' $filename
# فیلدهای شماره ‎1‎،‏ ‎5‎،‏ و ‎6‎ از فایل ‎$filename‎ را چاپ می‌کند.

awk '{print $0}' $filename
# کل فایل را چاپ می‌کند!
# مشابه همان اثر:  ‎cat $filename‎ . . . یا . . . ‎sed '' $filename‎

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

{ total += ${column_number} } 
#  مترجم: که در آن ‎column_number‎ شماره ستون مورد نظر در فایل است، به عنوان مثال می‌شود ‏$3‎ یا ‎$4‎ و غیره

این سطر، مقدار column_number را به مقدار فعلی total اضافه می‌کند. سرانجام، برای چاپ کردن مقدار «total»، یک بلوک فرمان END وجود دارد، که پس از آنکه اسکریپت تمام ورودی‌اش را پردازش نماید اجرا می‌گردد.
END { print total }

مشابه با END، به منظور اجرای یک بلوک کد قبل از اینکه awk پردازش ورودی‌اش را شروع نماید، یک BEGIN نیز وجود دارد .

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

مثال پایین نشان می‌دهد که چگونه awk می‌تواند ابزار تجزیه متن را به اسکریپت پوسته اضافه کند.

مثال ‎C-1‎. شمارش تعداد موارد حضور حروف

#! /bin/sh
# letter-count2.sh: شمارش حضور حرف در یک فایل متن.
#
#                    اسکریپت توسط ‎nyal [nyal@voila.fr]‎
#                 با مجوز در ‎ABS Guide‎ استفاده گردیده.
# قالب‌بندی و توضیح گذاری مجدد توسط نگارنده این راهنما.
#       ‎Version 1.1‎: ویرایش شده برای کار با ‎gawk 3.1.3‎
#              (باز هم در نگارش‌های قدیمی‌تر کار می‌کند.)


INIT_TAB_AWK=""
#             پارامتر برای مقدار دهی اولیه اسکریپت awk
count_case=0
FILE_PARSE=$1

E_PARAMERR=85

usage()
{
    echo "Usage: $0 file letters" 2>&1
    #     برای مثال:   ‎./letter-count2.sh filename.txt a b c‎
    exit $E_PARAMERR  # شناسه‌های داده شده به اسکریپت کم است.
}

if [ ! -f "$1" ] ; then
    echo "$1: No such file." 2>&1
    usage                 #    چاپ پیغام نحوه کاربرد و خروج.
fi 

if [ -z "$2" ] ; then
    echo "$2: No letters specified." 2>&1
    usage
fi 

shift                      #     حروف مشخص شده.
for letter in `echo $@`    # برای هر کدام . . .
  do
  INIT_TAB_AWK="$INIT_TAB_AWK tab_search[${count_case}] = \
  \"$letter\"; final_tab[${count_case}] = 0; " 
  #پارامتری که به اسکریپت awk پایین داده می‌شود.
  count_case=`expr $count_case + 1`
done

# اشکال‌زدایی:
# echo $INIT_TAB_AWK;

cat $FILE_PARSE |
#        لوله‌کشی فایل هدف به اسکریپت awk پایین.
# ---------------------------------------------------------------------
#                        نگارش قدیمی‌تر اسکریپت:
# awk -v tab_search=0 -v final_tab=0 -v tab=0 -v \
# nb_letter=0 -v chara=0 -v chara2=0 \

awk \
"BEGIN { $INIT_TAB_AWK } \
{ split(\$0, tab, \"\"); \
for (chara in tab) \
{ for (chara2 in tab_search) \
{ if (tab_search[chara2] == tab[chara]) { final_tab[chara2]++ } } } } \
END { for (chara in final_tab) \
{ print tab_search[chara] \" => \" final_tab[chara] } }"
# ---------------------------------------------------------------------
# همه اینها هیج پیچیده نیست، فقط چند حلقه‌ for،
#+            چند ‎if-test، و چند تابع اختصاصی.

exit $?

# این اسکریپت را با ‎letter-count.sh‎ مقایسه کنید.

برای مثال‌های ساده‌تر awk در داخل اسکریپت‌های پوسته، موارد زیر را ببینید:

  1. مثال ‎15-14‎

  2. مثال ‎20-8‎

  3. مثال ‎16-32‎

  4. مثال ‎36-5‎

  5. مثال ‎28-2‎

  6. مثال ‎15-20‎

  1. مثال ‎29-3‎

  2. مثال ‎29-4‎

  3. مثال ‎11-3‎

  4. مثال ‎16-61‎

  5. مثال ‎9-16‎

  6. مثال ‎16-4

  1. مثال ‎10-6‎

  2. مثال ‎36-19‎

  3. مثال ‎11-9‎

  4. مثال ‎36-4‎

  5. مثال ‎16-53‎

  6. مثال ‎T-3‎

این است تمام آنچه ما در باره awk پوشش می‌دهیم، اما مطالب بسیار بیشتری برای یادگیری وجود دارد. در کتابنامه مرجع‌های مرتبط را ببینید.

یادداشت‌ها

[1]

نام آن ناشی از حروف اول نام نویسندگان آن، ‎Aho‎،‏ ‎Weinberg‎،‏ و ‎Kernighan‎ می‌باشد.