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

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

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

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

بلوک‌های شرطی

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


4. بلوک‌های شرطی( if و test و ‎[[‎ )

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

    $ if  true
    > then echo "It was true."
    > else echo "It was false."
    > fi
    It was true.

در اینجا یک نمای کلی اساسی از if -statement ملاحظه می‌کنید.با فراخوانی دستور if با true شروع کرده‌ایم. true یک دستور داخلی است که همیشه به طور موفق خاتمه می‌یابد. if این دستور داخلی را اجرا می‌کند، و موقعیکه دستور اجرا شد، if کد خروج آن را بررسی می‌کند. چون true همواره به طور موفق خارج می‌شود، if با بلوک then ادامه می‌دهد، و کد را اجرا می‌کند. اگر به فرض دستور true به طریقی ناموفق می‌شد، و یک کد خروج عدم موفقیت صادر می‌کرد، دستور if از روی کد then عبور کرده و در عوض، کد بلوک else را اجرا می‌نمود.

افراد مختلف شیوه‌های متفاوتی از نوشتن جملات if را ترجیح می‌دهند. در اینجا برخی شیوه‌های رایج را می‌آوریم:

    if  commands
    then other commands
    fi
   -------------------
    if  commands
    then
        other commands
    fi
   -------------------
    if  commands; then
        other commands
    fi

چند دستور وجود دارد که به طور ویژه برای بررسی موارد و بازگرداندن وضعیت خروج نسبت به آنچه تشخیص می‌دهند، طراحی گردیده‌اند. اولین دستور از این قبیل test می‌باشد( که ‎ ‎[‎‎ نیز شناخته می‌شود.) یک نگارش پیشرفته‌تر آن ‎[[‎ نامیده می‌شود(مترجم: برای راحت خواندن این قسمت ‎[‎ را تست و ‎[[‎ را تست جدید بخوانید). ‎[‎ یا test یک دستور معمولی است که شناسه‌هایش را می‌خواند و برخی کنترل‌ها را با آنها انجام می‌دهد. ‎[[‎ خیلی مشابه ‎[‎ است، اما این استثنایی(یک کلمه‌کلیدی پوسته) می‌باشد که تنوع و تطبیق‌پذیری بیشتری ارائه می‌کند.بیایید به کار ببریم:

    $ if [ a = b ]
    > then echo "a is the same as b."
    > else echo "a is not the same as b."
    > fi
    a is not the same as b.

if دستور ‎[‎ را(به خاطر داشته باشید، که نیازی به یک if برای اجرای دستور ‎[‎ ندارید!)با شناسه‌های a و = و b و ] اجرا می‌کند. دستور ‎[‎ این شناسه‌ها را برای تعیین آنچه باید بررسی شود، به کار می‌برد. در این حالت، بررسی می‌کند که آیا رشته a (شناسه اول) مساوی(شناسه دوم) است با رشته b (شناسه سوم)، و اگر چنین باشد، به طور موفق خارج می‌شود. اگرچه، ما می‌دانیم که اینطور نیست، ‎[‎ به طور موفق خارج نمی‌شود(کد خروج آن 1 خواهد بود). if می‌بیند که دستور ‎[‎ به طور ناموفق خاتمه یافته است پس کد بلوک else را اجرا می‌کند.

حال ببینیم که چرا ‎[[‎ خیلی بیش از ‎[‎ جالب و مورد اعتماد است، اجازه دهید برخی مسائل محتمل با ‎[‎ را مشخص نماییم:

    $ myname='Greg Wooledge' yourname='Someone Else'
    $ [ $myname = $yourname ]
    -bash: [: too many arguments

می‌توانید حدس بزنید چه مشکلی موجب بروز خطا شده؟

دستور ‎[‎ با شناسه‌های Greg و Wooledge و = و Someone و Else و ] اجرا گردیده است. اینها ۶ شناسه هستند نه ۴ تا! دستور ‎[‎ نمی‌فهمد که اجرای چه آزمونی مورد انتظار است، زیرا انتظار دارد یکی از دو شناسه اول یا دوم، یک عملگر باشد. در وضعیت ما، عملگر سومین شناسه است. باز هم دلیل دیگری برای چرایی اهمیت شگرف نقل‌قولی نمودن. هنگامی که در Bash فضای سفیدی تایپ می‌کنیم که متعلق به کلمات قبل یا بعد آن می‌باشد، لازم است آن را نقل‌قولی کنیم، و همین طور هم برای بسط پارامترها:

    $ [ "$myname" = "$yourname" ]

در این حالت ‎[‎ دومین شناسه را یک عملگر(=) می‌بیند و می‌تواند به کارش ادامه دهد.

برای کمی مساعدت با ما، پوسته Korn یک سبک جدید بررسی شرطی را معرفی نموده(و BASH نیز آن را اخذ کرده). مؤلف اصل اینها که ‎[[‎ نامیده می‌شوند، پوسته کورن است. در ‎[[‎ چند ویژگی بسیار جالب گنجانیده شده است که در ‎[‎ غایب بودند.

یکی از ویژگیهای ‎[[‎ انطباق الگو است:

    $ [[ $filename = *.png ]] && echo "$filename looks like a PNG file"

ویژگی دیگر ‎[[‎ کمک به ما در ارتباط با بسط پارامترها می‌باشد:

    $ [[ $me = $you ]]           # Fine.
    $ [[ I am $me = I am $you ]] # Not fine!
    -bash: conditional binary operator expected
          -bash: syntax error near `am'

در این حالت، نیازی به نقل‌قولی کردن ‎$me‎ و ‎$you‎ نیست. چون ‎[[‎ یک دستور معمولی نیست(آن طور که‎[‎ هست)، بلکه یک کلمه کلیدی‌ shell می‌باشد، و قدرت جادویی مخصوصی دارد. این کلمه کلیدی شناسه‌هایش را قبل از اینکه آنها توسط Bash بسط داده شوند، تفکیک می‌کند و خودش بسط را انجام می‌دهد و نتیجه را به عنوان یک شناسه منفرد می‌گیرد، حتی اگر این نتیجه شامل فضای سفید هم باشد. (به بیان دیگر ‎[[‎ تفکیک کلمه روی شناسه‌هایش را اجازه نمی‌دهد.) به هرحال، هنوز هم مراقب باشید که رشته‌های ساده به طور صحیحی نقل‌قولی بشوند. زیرا ‎[[‎ نمی‌تواند تشخیص بدهد که آیا فضای سفید درجمله تعمدی است یا خیر، بنابراین آنها را مطابق روشی که BASH به طورمعمول انجام می‌دهد، تفکیک می‌کند. اجازه بدهید مثال را تصحیح کنیم:

    $ [[  "I am $me" = "I am $you" ]]

همچنین، تفاوت ظریف زیرکانه‌ای بین نقل‌قولی کردن و نکردن سمت راست مقایسه در ‎[[‎ وجود دارد. عملگر = وقتی طرف راست نقل‌قولی نشده باشد، به طور پیش‌فرض، انطباق الگو را انجام می‌دهد:

    $ foo=[a-z]* name=lhunath
    $ [[ $name = $foo ]] && echo "Name $name matches pattern $foo"
    Name lhunath matches pattern [a-z]*
    $ [[ $name = "$foo" ]] || echo "Name $name is not equal to the string $foo"
    Name lhunath is not equal to the string [a-z]*

بررسی اول کنترل می‌کند که آیا ‎$name‎ با الگوی محتوای ‎$foo‎ مطابقت دارد. دومین بررسی کنترل می‌کند که آیا ‎$name‎ مساوی رشته محتوای ‎$foo‎ می‌باشد. نقل‌قول‌ها به طور واقعی اختلاف آنها را خیلی زیاد نموده‌اند--سزاوار زیرکی نیست.

یادآوری: همواره اگر اطمینان ندارید نقل‌قولی کنید. اگر foo واقعاً به جای یک رشته شامل یک الگو باشد(موردی که خواستن آن نادر است -- به طور معمول الگوی شما به طور لفظی نوشته می‌شود: [[ ‎$name‎ = ‎[a-z]*‎ ]])، در اینجا شما یک خطای بی‌خطر دریافت می‌کنید و می‌توانید بیایید و آن را تصحیح کنید. اگر در نقل‌قول کردن سهل‌انگاری کنید، پیدا کردن باگ‌هامی‌تواند بسیار مشکل بشود، چون کد معیوب می‌تواند به طور فوری خرابی را بروز ندهد.

می‌توانید چندین دستور if را هم با استفاده از elif به جای else در یک جمله ترکیب کنید، که در آن هر بررسی نشانگر یک احتمال دیگر باشد:

    $ name=lhunath
    $ if [[ $name = "George" ]]
    > then echo "Bonjour, $name"
    > elif [[ $name = "Hans" ]]
    > then echo "Goeie dag, $name"
    > elif [[ $name = "Jack" ]]
    > then echo "Good day, $name"
    > else
    > echo "You're not George, Hans or Jack.  Who the hell are you, $name?"
    > fi

حال که درک مناسبی از مسائلی که با نقل‌قولها ممکن است ایجاد شود به دست آورده‌اید، بیایید به سایر ویژگی‌هایی که ‎[‎ و ‎[[‎ با آنها پر بار شده‌اند، نگاه کنیم:

  • بررسی‌هایی که با ‎[‎ ( که به عنوان test نیزشناخته می‌شود) پشتیبانی می‌شود:

    • ‎-e FILE‎: اگر فایل موجود باشد صحیح است.

    • ‎-f FILE‎: اگر فایل موجود معمولی باشد صحیح است.

    • ‎-d FILE‎: اگر فایل یک دایرکتوری باشد صحیح است.

    • ‎-h FILE‎: اگر فایل یک پیوند نمادین باشد صحیح است.

    • ‎-r FILE‎: اگر فایل برای شما قابل خواندن باشد صحیح است.

    • ‎-s FILE‎: اگر فایل موجود باشد وتهی نباشد صحیح است.

    • ‎-t FD ‎: اگر FD(توصیف‌گر فایل) در یک ترمینال باز شده باشد صحیح است.

    • ‎-w FILE‎: اگر فایل برای شما قابل نوشتن باشد صحیح است.

    • ‎-x FILE‎: اگر فایل برای شما قابل اجرا باشد صحیح است.

    • ‎-O FILE‎: اگر فایل به طور مؤثر در مالکیت شما باشد صحیح است.

    • ‎-G FILE‎: اگر فایل به طور مؤثر در مالکیت گروه شما باشد صحیح است.

    • ‎FILE -nt FILE‎: اگر فایل اول جدیدتر از فایل دوم باشد صحیح است.

    • ‎FILE -ot FILE‎: اگر فایل اول قدیمی‌تر از فایل دوم باشد صحیح است.

    • ‎-z STRING‎: اگر رشته تهی باشد(طول آن صفر باشد) صحیح است.

    • ‎-n STRING‎: اگر رشته تهی نباشد(طول آن صفر نباشد) صحیح است.

    • ‎STRING = STRING‎: اگر رشته اول از هر نظر مانند دومی باشد صحیح است.

    • ‎STRING != STRING‎: اگر رشته اول دقیقاً مانند رشته دوم نباشد صحیح است.

    • ‎STRING < STRING‎:اگر در مرتب‌سازی رشته اول قبل از دومی قرار می‌گیرد صحیح است.

    • ‎STRING > STRING‎: اگر رشته اول در مرتب‌سازی بعد از رشته دوم قرارمی‌گیرد صحیح است.

    • ‎EXPR -a EXPR‎: اگر هر دوعبارت صحیح باشندصحیح است(and منطقی).

    • ‎EXPR -o EXPR‎: اگر هر یک از دو عبارت صحیح باشد صحیح است(or منطقی).

    • ‎! EXPR‎: نتیجه عبارت را معکوس می‌کند( NOTمنطقی).

    • ‎INT -eq INT‎: اگر هر دو عدد صحیح دقیقاً برابر باشند صحیح است.

    • ‎INT -ne INT‎: اگر هر دو عدد صحیح دقیقاً برابر نباشند، صحیح است.

    • ‎INT -lt INT‎: اگر عدد صحیح اولی کوچکتر از دومی باشد صحیح است.

    • ‎INT -gt INT‎: اگر عدد صحیح اولی از دومی بزرگتر باشد صحیح است.

    • ‎INT -le INT‎: اگر عدد صحیح اولی کوچکتر یا مساوی دومی باشد صحیح است.

    • ‎INT -ge INT‎: اگر عدد صحیح اولی بزرگتر یا مساوی دومی باشد صحیح است.

  • بررسی‌های اضافی که فقط توسط ‎[[‎ پشتیبانی می‌شوند :

    • ‎STRING = (or ==) PATTERN‎: مانند ‎[‎ (یا test) مقایسه نمی‌کند، بلکه انطباق الگو انجام می‌شود. اگر رشته با الگوی جانشین منطبق گردد، صحیح است.

    • ‎STRING =~ REGEX‎: اگر رشته با الگوی regex(عبارت منظم)تطبیق کند، صحیح است.

    • ‎( EXPR )‎: پرانتزها می‌توانند برای تغییر اولویت ارزیابی‌ها به کار بروند.

    • ‎EXPR && EXPR‎: خیلی مشابه عملگر ‎ -a ‎  در test می‌باشد، اما اگر نتیجه عبارت اول صحیح نباشد، عبارت دوم ارزیابی نمی‌شود.

    • ‎EXPR || EXPR‎: خیلی مشابه عملگر ‎ -o ‎  در test می‌باشد، اما اگر نتیجه عبارت اول صحیح باشد، عبارت دوم ارزیابی نمی‌شود.

چند مثال؟ حتماً:

    $ test -e /etc/X11/xorg.conf && echo 'Your Xorg is configured!'
    Your Xorg is configured!
    $ test -n "$HOME" && echo 'Your homedir is set!'
    Your homedir is set!
    $ [[  boar != bear ]] && echo "Boars aren't bears."
    Boars aren't bears!
    $ [[  boar != b?ar ]] && echo "Boars don't look like bears."
    $
    $ [[  $DISPLAY ]] && echo "Your DISPLAY variable is not empty, you probably have Xorg running." 
    Your DISPLAY variable is not empty, you probably have Xorg running.
    $ [[  ! $DISPLAY ]] && echo "Your DISPLAY variable is not not empty, you probably don't have Xorg running."
    $


  • تکرارمفید:
    هنگامی که یک اسکریپت BASH ایجاد می‌کنید، همیشه باید از ‎[[‎ به جای ‎[‎ استفاده کنید.
    وقتی یک اسکریپت پوسته می‌نویسید، که پس از اتمام ممکن است در محیطی که BASH در دسترس نباشد، به کار برود، باید از ‎[‎ استفاده کنید، به دلیل آنکه به مراتب قابل حمل‌تر می‌باشد. ( در حالیکه در BASH و برخی پوسته‌های دیگر، ‎[‎ یک دستور داخلی است، به صورت یک برنامه خارجی نیز به خوبی در دسترس می‌باشد، یعنی به عنوان شناسه مثلاً exec و xargs کار خواهد کرد.)
    هرگز از ‎ -a ‎ یا ‎ -o ‎ در بررسی‌های فرمان ‎[‎ استفاده نکنید. به جای آن از فرمان‌های چندگانه ‎[‎ ( یا اگر می‌توانید از ‎[[‎ ) استفاده کنید. استاندارد POSIX رفتار ‎[‎ در مجموعه بررسی‌های پیچیده را تعریف نکرده، بنابراین هرگز نمی‌دانید چه رفتاری حاصل می‌شود.

        if  [ "$food" = apple ] && [ "$drink" = tea ]; then
          echo "The meal is acceptable."
        fi




  • if (کلمه‌کلیدی): لیستی از دستورات را اجرا می‌کند و سپس نسبت به کد خروج آنها، کد بلوک then ( بخش اختیاری else) را اجرا می‌نماید.


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

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