مبانی

مبانی

تمرین یادگیری

مقدمه

مبانی

ما به زبان با نام AWK و به برنامه‌ی اجرایی‌ای که برنامه‌های AWK را تفسیر می‌کند با نام awk یا gawk اشاره می‌کنیم.

الگو و کنش

یک برنامه‌ی AWK از جفت‌های الگو-کنش تشکیل شده است.

pattern1 { action1 }
pattern2 { action2 }
...

یک الگو می‌تواند یک عبارت باقاعده باشد که با ورودی مطابقت داده می‌شود. همچنین می‌تواند هر عبارتی باشد که نتیجه‌اش یک مقدار «درست» یا «غلط» است.

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

اگر نتیجه‌ی الگو «درست» باشد، کنش متناظر با آن ارزیابی می‌شود.

رکورد و فیلد

AWK ورودی را به‌صورت زنجیره‌ای از رکوردها تجزیه می‌کند. هر رکورد به صفر یا چند فیلد تقسیم می‌شود.

رفتار پیش‌فرض چنین است:

  • تقسیم ورودی به رکوردها با استفاده از خط جدید به‌عنوان «جداکننده‌ی رکورد»، به‌طوری که هر خط یک رکورد است.
  • تقسیم رکورد به فیلدها با استفاده از فضای سفید به‌عنوان «جداکننده‌ی فیلد»، به‌طوری که هر کلمه یک فیلد است.

الگو و کنش، ادامه

می‌توان الگو را حذف کرد؛ در این صورت کنش برای هر رکورد ورودی ارزیابی می‌شود.

می‌توان کنش را هم حذف کرد؛ در این صورت کنش پیش‌فرض، چاپ رکورد جاری است.

الگوهای خاص

دو الگوی خاص وجود دارند که اغلب استفاده می‌شوند.

  • BEGIN کنش مرتبط را پیش از مصرف هر ورودی ارزیابی می‌کند.
  • END کنش مرتبط را پس از مصرف تمام ورودی ارزیابی می‌کند.

متغیرهای فیلد

به فیلدها با $1، $2، $3 و غیره اشاره می‌کنید.

رکورد جاری $0 است.

در ادامه چند متغیر توکار پرکاربرد دیگر را می‌بینید.

متغیرهای توکاری که تجزیه‌ی ورودی را کنترل می‌کنند
  • RS جداکننده‌ی رکورد ورودی است. همان‌طور که گفته شد، مقدار پیش‌فرض آن خط جدید است.
  • FS جداکننده‌ی فیلد ورودی است.

این متغیرها اغلب در بلوک کنش BEGIN تنظیم می‌شوند.

متغیرهای توکاری که اطلاعات را منتقل می‌کنند

این متغیرها در طول اجرای برنامه به‌طور خودکار توسط AWK تنظیم می‌شوند.

  • NF تعداد فیلدهای رکورد جاری را نگه می‌دارد.
    • برای به‌دست آوردن مقدار آخرین فیلد، از $NF استفاده کنید.
  • NR شماره‌ی رکورد جاری را نگه می‌دارد.
    • وقتی چند فایل ورودی پردازش می‌شوند، NR تعداد کل رکوردهای پردازش‌شده تا این لحظه را نگه می‌دارد.
  • FNR شماره‌ی رکورد جاری در فایل ورودی جاری را نگه می‌دارد.
    • برای نشان دادن تفاوت میان NR و FNR، یک اصطلاح رایج AWK را می‌بینید.
      NR == FNR {action}
      
      این یعنی «اگر شماره‌ی رکورد انباشته با شماره‌ی رکورد فایل جاری برابر باشد.» این تنها می‌تواند برای رکوردهای اولین فایل ورودی درست باشد.

مفهوم درستی

AWK همان مفهوم درستی را مانند C به کار می‌برد.

  • عدد 0 «غلط» است.
  • هر عدد دیگری «درست» است.

از آنجا که AWK یک زبان پردازش متن است، مقادیر درستی به رشته‌ها هم گسترش می‌یابند.

  • یک رشته‌ی خالی "" «غلط» است.
  • هر رشته‌ی ناتهی «درست» است.

توضیح

توضیح با نویسه‌ی # شروع می‌شود و تا پایان خط ادامه می‌یابد.

مثال

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

برای فهرست کردن اسم‌های کاربری:

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

توجه کنید که کنش {print $1} الگویی ندارد، پس برای هر رکورد اجرا می‌شود.

اگر بخواهیم خروجی را فقط به کاربرانی محدود کنیم که از bash به‌عنوان پوسته‌ی ورود خود استفاده می‌کنند، می‌توانیم این کار را انجام دهیم:

awk '
    BEGIN { FS = ":" }
    $7 == "/bin/bash" { print $1 }
' /etc/passwd

دستورالعمل‌ها

روزی روزگاری، شهر پرجنب‌وجوشی به نام Cyberspace وجود داشت. Cyberspace یک کلان‌شهر دیجیتال بود که هر روز میلیون‌ها ساکن به آن وارد و از آن خارج می‌شدند. برای پیگیری همه‌ی این کاربران، Cyberspace فایل ویژه‌ای به نام /etc/passwd داشت.

فایل /etc/passwd مثل دفترچه تلفن شهر بود. هر کاربری را که روی سیستم حساب داشت فهرست می‌کرد، همراه با اطلاعات مهمی درباره‌ی هر کاربر:

n فیلد
۱ نام کاربری
۲ گذرواژه («x» نشان می‌دهد که گذرواژه‌ی واقعی برای امنیت جای دیگری ذخیره شده است)
۳ UID، شناسه‌ی عددی یکتای کاربر
۴ GID، شناسه‌ی عددی یکتای گروه (معمولاً همان UID)
۵ اطلاعات کاربر (معمولاً اسم کامل کاربر، اما می‌تواند اطلاعات دیگری هم دربر داشته باشد)
۶ پوشه‌ی خانه
۷ شل ورود

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

glennj:x:1010:1010:Glenn Jackman:/home/glennj:/usr/local/bin/fish

فایل را تیمی از مدیران سیستم اداره می‌کردند که مسئول ساختن حساب‌های جدید، به‌روزرسانی حساب‌های موجود و حذف حساب‌های قدیمی بودند. مدیران سیستم دروازه‌بانان Cyberspace بودند و مطمئن می‌شدند که فقط کاربران مجاز به سیستم دسترسی داشته باشند.

یک روز، مدیر سیستم تازه‌ای به نام Alex استخدام شد تا به تیم بپیوندد. Alex از پذیرفتن این کار هیجان‌زده بود و خیلی زود همه‌ی ریزه‌کاری‌های فایل /etc/passwd را یاد گرفت. یاد گرفت چطور کاربران جدید به سیستم اضافه کند، اطلاعات کاربران را به‌روزرسانی کند و کاربران قدیمی را حذف کند.

وقتی Alex داشت روی فایل /etc/passwd کار می‌کرد، به نکته‌ی عجیبی پی برد. پوشه‌ی خانه‌ی بعضی کاربران عجیب یا غیرمعمول بود. پوشه‌ی خانه‌ی بعضی کاربران روی /dev/null تنظیم شده بود و پوشه‌ی خانه‌ی بعضی دیگر روی مسیرهای عجیبی که اصلاً وجود نداشتند.

Alex فهمید که این کاربران افراد واقعی نیستند، بلکه حساب‌های جعلی‌ای هستند که هکرها ساخته‌اند. هکرها راهی پیدا کرده بودند که از یک آسیب‌پذیری در سیستم سوءاستفاده کنند و این حساب‌های جعلی را ساخته بودند تا به Cyberspace دسترسی پیدا کنند.

Alex می‌دانست که باید دست به کار شود. او از awk استفاده کرد تا فایل /etc/passwd را تحلیل کند و اسکریپتی نوشت که همه‌ی حساب‌های جعلی را شناسایی کند. سپس با بقیه‌ی اعضای تیم همکاری کرد تا این حساب‌ها را حذف کنند و آسیب‌پذیری‌ای را که در وهله‌ی اول به هکرها امکان ساخت آن‌ها را داده بود، رفع کنند.

به لطف استفاده‌ی Alex از awk، تیم توانست حساب‌های جعلی را شناسایی و حذف کند و Cyberspace را به جای امن‌تری برای همه تبدیل کند. مدیران سیستم همچنان فایل /etc/passwd را مدیریت می‌کردند، آن را به‌روز و امن نگه می‌داشتند و مطمئن می‌شدند که فقط کاربران مجاز به سیستم دسترسی داشته باشند.

حالا نوبت شماست که مثل Alex مدیر سیستم باشید.

Note

در اینجا چند نکته‌ی اضافی از نحوه‌ی نگارش AWK را می‌بینید که برای حل این تمرین به آن‌ها نیاز دارید.

  • عملگرهای منطقی شبیه زبان‌های دیگر هستند:

    عمل مثال
    AND expr1 && expr2
    OR expr1 || expr2
    NOT ! expr
  • فراخوانی یک تابع نحوه‌ی نگارش آشنایی دارد:

    function greet(name) {
        print "Hello", name
    }
    BEGIN {
        greet("Mary")   # prints "Hello Mary"
    }
    

1. فهرست کردن نام‌های کاربری

یک برنامه‌ی awk بنویسید که اولین فیلد جداشده با دونقطه را برای هر خط در فایل passwd چاپ کند.

2. چاپ شماره‌ی خط‌ها

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

3. چاپ رکوردهای دارای پوشه‌ی خانه‌ی نامعتبر

در Cyberspace، پوشه‌ی خانه‌ی «معتبر» با /home یا /root شروع می‌شود. رکوردهای فایل ورودی را که پوشه‌ی خانه‌ی نامعتبر دارند چاپ کنید.

4. چاپ کاربران معتبری که از bash استفاده می‌کنند

رکوردهایی را چاپ کنید که پوشه‌ی خانه‌شان معتبر است و شل ورودشان bash است.


منبع

گفت‌وگو با ChatGPT
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
AWK Exercism

آماده‌اید مبانی را شروع کنید؟

در Exercism ثبت‌نام کنید تا AWK را همراه با 3 مفهوم92 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.