آموزش‌های خط فرمانی

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

آموزش‌های خط فرمانی

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

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

ادامه یادداشت قبل


3. گروه‌بندی دستورات

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

فرض کنید می‌خواهید یک فایل را در صورت وجود کلمه معین "good" در آن و نیز عدم وجود کلمه مشخص "bad" در آن حذف کنید. با استفاده از grep ( فرمانی که ورودی‌اش را برای الگوهای تعیین شده بررسی می‌کند)، این شرایط را به این صورت ترجمه می‌کنیم:

grep -q goodword "$file" #exit status 0 (success) if "$file" contains 'goodword'
! grep -q "badword" "$file" #exit status 0 (success) if "$file" does not contain 'badword'

ما از گزینه ‎-q‎‏(quiet)‏ با فرمان grep استفاده کردیم چون نمی‌خواهیم موارد انطباق را به خروجی ارسال کند، فقط می‌خواهیم کد خروج را تنظیم کند.

علامت ! در جلوی دستور موجب می‌شود Bash وضعیت خروج فرمان را نفی کند. اگر دستور صفر(موفقیت) را برگرداند، کاراکتر ! آن را به عدم موفقیت تبدیل می‌کند، و برعکس، اگر کد غیر صفر(عدم موفقیت) برگرداند، کاراکتر ! آن را به موفقیت تبدیل نماید.

حال برای متصل کردن این شرط‌ها به یکدیگر و ربط دادن حذف فایل به موفقیت هر دو، می‌توانستیم از عملگرهای شرطی استفاده کنیم:

    $ grep -q goodword "$file" && ! grep -q badword "$file" && rm "$file"

این بخوبی کار می‌کند( در حقیقت می‌توانیم هر تعداد از &&ها که می‌خواهیم بدون مشکل با هم زنجیر کنیم ). حالا فرض کنید می‌خواهیم در حالتی که حذف فایل ناموفق باشد، یک پیغام خطا نمایش بدهیم:

    $ grep -q goodword "$file" && ! grep -q badword "$file" && rm "$file" || echo "Couldn't delete: $file" >&2

این هم ظاهراً در نگاه اول صحیح است. اگر کد خروج rm برابر 0(موفقیت) نباشد،سپس عملگر || ماشه اجرای دستور بعدی را می‌ کشد و echo پیغام خطا را نمایش می‌دهد(‎>&2‎ در خروجی استاندارد خطا).

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

همچنین تصور کنید اولین grep ناموفق است(کد وضعیت یک می‌شود) . Bash حالا && بعدی را می‌بیند، بنابراین به طور کلی دومین grep را نادیده می‌گیرد. بعد یک && دیگر می‌بیند، بنابراین از دستور rm که بعد از آن است نیز عبور می‌کند. عاقبت یک عملگر || می‌بیند. آها! وضعیت خروج ناموفق است، و ما یک عملگر || داریم، پس Bash دستور echo را اجرا می‌کند، و به ما می‌گوید که نمی‌تواند فایل را حذف کند ولواینکه هرگز اقدام به این عمل نکرده است! و این چیزی نیست که ما می‌خواهیم.

وقتی فقط پیغام خطای اشتباهی دریافت می‌کنید انعکاس خیلی بدی ندارد، اما اگر دقیق نباشید، سرانجام در کدهای خطرناک‌تر، این اتفاق خواهد افتاد. شما که نمی‌خواهید به طور تصادفی در اثر نارسایی منطق برنامه خود فایلی را حذف یا رونویسی نمایید!

نقص منطق ما در این واقعیت است که ما می‌خواهیم فرمان‌های rm و echo وابسته به یکدیگر باشند. دستور echo مربوط به rm می‌باشد، نه مربوط به grepها. بنابراین آنچه ما لازم داریم، گروه‌بندی آنها است. گروه‌بندی با استفاده از ابروها انجام می‌گردد:

    $ grep -q goodword "$file" && ! grep -q badword "$file" && { rm "$file" || echo "Couldn't delete: $file" >&2; }

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

حالا دستورات rm و echo را با هم گروه‌بندی نموده‌ایم. این به طورمؤثر و کارامدی به معنای آنست که گروه به عنوان یک جمله در نظر گرفته می‌شود، نه چند دستور. برگردیم به موقعیتی که اولین دستور grep ما ناموفق بود، حالا BASH به جای اینکه به جمله ‎&& rm "$file"‎ رسیدگی کند، جمله ‎&& { ... }‎ را بررسی می‌کند. چون یک عملگر && مقدم بر این جمله است و آخرین دستور اجرا شده ناموفق بوده(دستور ناموفق grep)، از روی این گروه عبور کرده به پیش می‌رود.

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

    {
        read firstLine
        read secondLine
        while read otherLine; do
            something
        done
    } < file

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

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

    cd "$appdir" || { echo "Please create the appdir and try again" >&2; exit 1; }

ادامه دارد ....

نظرات 0 + ارسال نظر
ایمیل شما بعد از ثبت نمایش داده نخواهد شد