پارامترها - آموزش اسکریپت نویسی
X
تبلیغات
رایتل

آموزش اسکریپت نویسی

آموزش اسکریپت نویسی پوسته گنو-لینوکس

#!/bin/bash

پارامترها



پارامترها

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

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

  • نام: یک کلمه فقط متشکل ازحروف، ارقام، و خط‌زیر( runderscore ) است، که با یک حرف یا یک خط‌زیر شروع بشود. همچنین به عنوان یک شناسه به آن رجوع می‌شود.

برای ذخیره داده در یک متغیر، از ترکیب دستوری تخصیص به شکل زیر استفاده می‌کنیم:

    $ varname=vardata

این دستور مقدار vardata را به متغیری به نام varname اختصاص می‌دهد.

لطفاً توجه نمایید که نمی‌توانید از فاصله در اطراف علامت تخصیص = استفاده کنید. اگر این را بنویسید:

    # This is wrong!
    $ varname = vardata

BASH متوجه نخواهد شد که سعی می‌کنید یک تخصیص انجام دهید. تفکیک کننده varname را بدون = می‌بیند و با آن همچون نام یک فرمان رفتار می‌کند، و بعد هم = و vardata را به عنوان شناسه‌های آن عبور می‌دهد.

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

برای تشریح آنکه بسط پارامتر چیست، بیایید از مثال استفاده کنیم:

    $ foo=bar
    $ echo "Foo is $foo"

وقتی Bash می‌خواهد کد شما را اجرا کند، اول دستور شما را با گرفتن نتیجه بسط پارامتر(‎ $foo‎)، و تعویض آن با محتوای foo، که bar است، تغییر می‌دهد. دستور اینطور می‌شود:

    $ echo "Foo is bar" 

اکنون Bash آماده اجرای فرمان است. اجرای آن یک جمله ساده در صفحه نمایش نشان می‌دهد.

    Foo is bar

اهمیت دارد بدانیم که بسط پارامتر موجب می‌شود که ‎$parameter‎ با محتوای آن تعویض گردد، به علت حالت زیر که به استناد فهم مبحث تفکیک شناسه در فصل قبل می‌باشد :

    $ song="My song.mp3"
    $ rm $song
    rm: My: No such file or directory
          rm: song.mp3: No such file or directory

چرا این عمل نمی‌کند؟ به علت آنکه Bash، جمله ‎$song‎ شما را با محتوای متغیر تعویض نموده، که My song.mp3 شده است، سپس تفکیک کلمه را انجام داده، و فقط پس از آن دستور را اجرا کرده است. و این مانند آن است که تایپ کرده باشید:

    $ rm My song.mp3

و بر اساس قواعد تفکیک کلمه، Bash گمان می‌برد که منظور شما My و song.mp3 به معنی دو فایل مختلف است، زیرا بین آنها فضای سفید وجود دارد و نقل‌قولی هم نشده است. چطور آن را رفع کنیم؟ به خاطر بسپاریم که در اطراف هر بسط پارامتر، نقل‌قول دوگانه را قرار بدهیم!

    $ rm "$song"


  • پارامترها: پارامترها داده‌هایی که می‌توانند به واسطه یک نشانه یا نام بازیابی بشوند را ذخیره می‌کنند.


پارامترهای خاص و متغیرها

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

 
    $ # Some parameters that aren't variables:
    $ echo "My shell is $0, and has these options set: $-"
    My shell is -bash, and has these options set: himB
    $ # Some parameters that ARE variables:
    $ echo "I am $LOGNAME, and I live at $HOME."
    I am lhunath, and I live at /home/lhunath.

لطفاً توجه نمایید: برخلاف PHP و Perl ...پارامترها با علامت $ شروع نمی‌شوند.علامت $ که شما در مثال مشاهده می‌کنید، صرفاً موجب می‌شود که پارامتر ذکر شده بعد از آن، بسط داده شود. بسط اساساً به معنای آنست که پوسته پارامتر را با محتوای آن تعویض می‌کند. به این ترتیب، LOGNAME پارامتری( متغیری ) است که محتوای آن نام کاربری شماست. ‎$LOGNAME‎ عبارتی است که با محتوای آن متغیر تعویض خواهد شد، که در این حالت lhunath است.

گمان می‌کنم حالا، مقصود را دریافته‌اید. در اینجا خلاصه‌ای از اکثر پارامترهای ویژه:

  • 0: محتوی نام یا مسیر اسکریپت است( این در همه حال صدق نمی‌کند. )

  • پارامترهای موضعی(مکانی): 1, 2, 3 ...، اینها محتوی شناسه‌هایی می‌باشند که ما به اسکریپت یا تابع جاری می‌دهیم.

  • *: به همه کلمات تمام پارامترهای موضعی بسط می‌یابد. اگر نقل‌قول دوگانه بشود، به یک رشته منفرد شامل تمام پارامترهای موضعی بسط می‌یابد، که با اولین کاراکتر متغیر IFS ( که بعد در باره‌اش صحبت می‌کنیم)، از یکدیگر جدا شده‌اند.

  • @: به تمام کلمات پارامترهای موضعی بسط می‌یابد، اگر نقل‌قول دوگانه بشود، به لیستی از تمام کلمات پارامترهای موضعی به صورت کلمه‌های منفرد، بسط می‌یابد.

  • #: به عدد معادل تمام پارامترهای موضعی(مکانی) ارائه شده فعلی، بسط می‌یابد.

  • ?: به کد خروج آخرین فرمان تکمیل شده در پیش‌زمینه، بسط می‌یابد.

  • $: به PID ( شماره ID پردازش) پوسته جاری، بسط می‌یابد.

  • !: به PID آخرین دستور اجرا شده در پس‌زمینه، بسط می‌یابد.

  • _: به آخرین شناسه آخرین فرمانی که اجرا شده است، بسط داده می‌شود.

و در اینجا چند مثال از متغیرهایی که پوسته برای شما فراهم می‌کند:

  • BASH_VERSION: محتوی رشته‌ایست که شماره نگارش BASH را شرح می‌دهد.

  • HOSTNAME: شامل نام میزبان کامپیوتر شما می‌باشد، به شکل کوتاه یا بلند، بستگی به چگونگی تنظیمات کامپیوتر شمادارد.

  • PPID: محتوی شماره شناسایی پردازش(PID) پردازش والد پوسته جاری است.

  • PWD: محتوی دایرکتوری کاری جاری است.

  • RANDOM: هرگاه این متغیر را بسط بدهید، یک عدد تصادفی(ساختگی) بین 0 تا 32767 تولید می‌شود.

  • UID:شماره شناسایی(ID) کاربر فعلی . نامعتبر برای مقاصد امنیتی یا تأییدی، افسوس.

  • COLUMNS: تعداد کاراکترهایی که می‌تواند یک سطر از ترمینال شما را پر کند(عرض ترمینال شما بر حسب کاراکتر).

  • LINES: تعداد سطرهایی که ترمینال جاری شما را پر می‌کند(ارتفاع ترمینال بر حسب سطر).

  • HOME: دایرکتوری خانگی کاربر فعلی.

  • PATH: یک لیست از مسیرها، که با کاراکتر کولن ازیکدیگر جدا شده‌اند، و در صورتیکه یک فرمان، مستعار ، تابع، دستور داخلی، و کلمه کلیدی نباشد، و مسیر آن نیز تعیین نشده باشد، برای یافتن آن دستور جستجو می‌شوند.

  • PS1: شامل رشته‌ایست که اعلان پوسته شما را تشریح می‌کند.

  • TMPDIR: شامل دایرکتوری مورد استفاده پوسته برای نگهداری فایل‌های موقتی آن، می‌باشد.

(خیلی بیشتر از اینها وجود دارد-- برای لیست جامع، مستندات را ملاحظه نمایید.) البته، شما محدود به این متغیرها نمی‌باشید. هرطور که مایلید متغیرهای خودتان را تعریف کنید:

    $ country=Canada
    $ echo "I am $LOGNAME and I currently live in $country."
    I am lhunath and I currently live in Canada.

توجه داشته باشید که ما کمیت Canada را به متغیر country اختصاص دادیم. به یاد داشته باشید که شما مجاز به قرار دادن فاصله، قبل و بعد از علامت تساوی نمی‌باشید!

    $ language = PHP
    -bash: language: command not found
    $ language=PHP
    $ echo "I'm far too used to $language."
    I'm far too used to PHP.

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

    $ ls
    no secret  secret
    $ file='no secret'
    $ rm $file
    rm: cannot remove `no': No such file or directory

فرض کنید ما دو فایل no secret و secret داریم. اولی محتوی چیز ارزشمندی نیست، اما دومی محتوی اطلاعات سری است، که جهان را از سرنوشت بد(نابودی) رهایی می‌بخشد. ملاحظه کنید که اگر نقل‌قولی کردن بسط پارامتر file را فراموش کنید. BASH پارامتر را بسط می‌دهد ونتیجه آن ‎ rm no secret می‌شود. BASH مطابق معمول شناسه‌ها را نسبت به فضای سفید آنها تفکیک می‌کند، و به فرمان rm دو شناسه تحویل می‌دهد: 'no' و 'secret'. درنتیجه موفق به یافتن فایل no نمی‌شود و اما فایل secret را حذف می‌کند. فایل secret از دست می‌رود!


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




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

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


انواع متغیر

اگر چه BASH یک زبان تیپیک نیست، چند نوع متغیر متفاوت دارد. این گروه‌ها، نوع کمیتی که می‌توانند داشته باشند را مشخص می‌کنند. اطلاعات نوع متغیر به طور داخلی توسط Bash نگهداری می‌شوند.

  • آرایه: ‎ دستور declare -a variable‎: یک متغیر که آرایه‌ای از رشته‌هاست، تعریف می‌کند.

  • آرایه‌ انجمنی(شرکت‌پذیر): ‎ دستور declare -A variable‎: یک متغیر آرایه‌ای شرکت پذیر از رشته‌ها تعریف می‌کند(bash نگارش 4.0 یا بالاتر).

  • عدد صحیح: دستور ‎declare -i variable‎: یک متغیر نگاهدارنده عدد صحیح تعریف می‌کند. تخصیص مقدار به این متغیر، به طور خودکار ارزیابی حسابی را فعال می‌کند.

  • فقط خواندنی: دستور ‎declare -r variable‎: متغیری تعریف می‌کند که نمی‌تواند اصلاح یا حذف شود.

  • Export: دستور ‎declare -x variable: متغیر را به صورت صادر نمودنی تعریف می‌کند، یعنی می‌تواند به زیرپوسته‌ها یا پردازش فرزند به ارث برسد.

آرایه‌ها اساساً لیست شاخص‌گذاری شده‌ای از رشته‌ها هستند. اینها به جهت قابلیت نگهداری چندین رشته همراه یکدیگر، بدون استناد به جداکننده برای تفکیک آنها از هم(که انجام صحیح آن کسل‌کننده و درغیر آن‌صورت متمایل به خطا هستند)، خیلی مناسب می‌باشند.

تعریف متغیرها به عنوان عدد صحیح، این مزیت را دارد، که موقع تخصیص و اصلاح آنها می‌توانید از برخی ترکیب‌های دستوری( syntax)صرفنظر کنید:

    $ a=5; a+=2; echo $a; unset a
    52
    $ a=5; let a+=2; echo $a; unset a
    7
    $ declare -i a=5; a+=2; echo $a; unset a
    7
    $ a=5+2; echo $a; unset a
    5+2
    $ declare -i a=5+2; echo $a; unset a
    7

هرچندکه، در عمل استفاده از   declare -i به اندازه زیادی کمیاب است. به طور عمده، این به علت ایجاد رفتاری است، که برای شخصی که از اسکریپت نگهداری می کند و به وجود دستور declare اشراف ندارد ، شگفت‌آور خواهد بود. اکثر اسکریپت نویسان ورزیده، ترجیح می‌دهند، وقتی می‌خواهند محاسبات انجام دهند، از دستورات صریح حسابی let یا ‎((...))‎، استفاده کنند.

همچنین یک تعریف صریح از یک آرایه با استفاده از ‎declare -a‎ به ندرت می‌بینید. نوشتن ‎array=(...)‎ کافی است و Bash آگاه خواهد شد که اکنون متغیر یک آرایه است. به استثنای آرایه شرکت‌پذیر، که باید به طور صریح تعریف شود، یعنی: declare -A myarray.


  • رشته: یک رشته، توالی از کاراکترها می‌باشد.

  • آرایه: یک آرایه لیستی از رشته هامی‌باشد، که با اعداد شاخص‌گذاری شده‌اند.

  • عدد صحیح: یک عدد کامل مثبت، منفی، یا صفر می‌باشد.

  • فقط خواندنی: پارامترهایی که فقط خواندنی هستند نمی‌توانند حذف یا اصلاح شوند.

  • Export: متغیرهایی که به عنوان صادر کردنی علامت خورده‌اند به هر زیرپوسته یا پردازش فرزند به ارث می‌رسند.



بسط پارامتر

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

    $ echo "'$USER', '$USERs', '${USER}s'"
    'lhunath', '', 'lhunaths'

این مثال شرح می‌دهد که اساس بسط پارامتر(PE) چگونه است. دومین PE به یک رشته تهی منجر می‌شود. به علت آنکه پارامتر USERs تهی است. هدف ما این نبود که s بخشی از نام پارامتر باشد. چون به این طریق BASH نمی‌تواند بداند که شما می‌خواهید یک s لفظی به محتوای پارامتر پیوست کنید، لازم است از ابروها برای علامت گذاری ابتدا و انتهای نام پارامتر استفاده کنید. آنچه که ما در سومین PE در مثال فوق انجام داده‌ایم.

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

    $ for file in *.JPG *.jpeg
    > do mv "$file" "${file%.*}.jpg"
    > done

کد بالا می‌تواند برای تغییر نام همه فایل‌های JPEG با پسوند ‎ .JPG‎ یا ‎.jpeg‎ به فایل با پسوندمعمول ‎.jpg‎ استفاده شود. عبارت ‎${file%.*}‎ قسمتی ازانتهایی‌ترین بخش نام فایل که با نقطه(.) شروع شده باشد، را جدا می‌کند. سپس در همان نقل‌قول، پسوند جدید به انتهای نتیجه حاصل از بسط افزوده می‌شود.

در اینجا خلاصه‌ای ازاکثر ترفندهای PE که معتبر هستند آمده است:

  • ${parameter:-word}‎: مقادیر پیش‌فرض استفاده می‌شود. اگر parameter موجود نباشد یا تهی باشد، بسط word جایگزین می‌گردد. در غیر آن‌صورت، مقدار parameter جایگزین می‌گردد.

  • ${parameter:=word}‎: تخصیص مقدار پیش‌فرض. اگر parameter موجود نباشد یا تهی باشد، بسط word به parameter تخصیص داده می‌شود. سپس مقدار parameterجایگزین می‌شود.

  • ${parameter:+word}‎: استفاده از مقدار جایگزین. اگر parameter موجود نباشد یا تهی باشد، چیزی جایگزین نمی‌شود، در غیر آنصورت بسط word جایگزین می‌گردد.

  • ${parameter:offset:length}‎ بسط زیر رشته(قسمتی از رشته). به تعداد length کاراکتر از parameter با شروع ازکاراکتری که محل آن توسط offset تعیین شده(شمارش از صفر است)، بسط می‌یابد. اگر :length از قلم افتاده باشد، تا انتها را شامل می‌شود. اگر offset منفی باشد(از پرانتز استفاده شود!)، به جای شمارش از ابتدای parameter به جلو، از انتها به طرف عقب انجام می‌شود.

  • ${#parameter}‎: تعداد کاراکترهایی به اندازه مقدار parameter جایگزین می‌گردد.

  • ${parameter#pattern}‎: الگوی pattern از ابتدای parameter مطابقت داده می‌شود. نتیجه بسط، جایگزینی باقیمانده parameter پس ار حذف کوتاهترین انطباق با الگو خواهد بود.

  • ${parameter##pattern}‎: مانند مورد فوق، اما با حذف بلندترین مورد انطباق.

  • ${parameter%pattern}‎: الگوی pattern با انتهای ، parameter مطابقت داده می‌شود. نتیجه، زیر رشته‌ای از parameter است که پس از حذف کوتاه‌ترین انطباق حاصل می‌شود.

  • ${parameter%%pattern}‎: مانند مورد فوق، اما بلندترین انطباق حذف می‌گردد.

  • ${parameter/pattern/string}‎: از چپ به راست parameter را جستجو نموده و اولین انطباق pattern را با رشته string تعویض می‌کند.

  • ${parameter//pattern/string}‎: مانند مورد فوق، اماهمه موارد انطباق pattern، تعویض می‌شوند.

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

 
    $ file="$HOME/.secrets/007"; \
    > echo "File location: $file"; \
    > echo "Filename: ${file##*/}"; \
    > echo "Directory of file: ${file%/*}"; \
    > echo "Non-secret file: ${file/secrets/not_secret}"; \
    > echo; \
    > echo "Other file location: ${other:-There is no other file}"; \
    > echo "Using file if there is no other file: ${other:=$file}"; \
    > echo "Other filename: ${other##*/}"; \
    > echo "Other file location length: ${#other}"
    File location: /home/lhunath/.secrets/007
    Filename: 007
    Directory of file: /home/lhunath/.secrets
    Non-secret file: /home/lhunath/.not_secret/007

    Other file location: There is no other file
    Using file if there is no other file: /home/lhunath/.secrets/007
    Other filename: 007
    Other file location length: 26

تفاوت میان ‎${v#p}‎ و ‎${v##p}‎ را به خاطر بسپارید. دوتایی شدن کاراکتر #به آن معنی است که، الگوها حریص(پر خور) می‌شوند. همین مطلب برای % نیز صادق است:

 
    $ version=1.5.9; echo "MAJOR: ${version%%.*}, MINOR: ${version#*.}."
    MAJOR: 1, MINOR: 5.9.
    $ echo "Dash: ${version/./-}, Dashes: ${version//./-}."
    Dash: 1-5.9, Dashes: 1-5-9.

توجه: نمی‌توانید PEهای چندگانه را با هم به کار ببرید. اگر نیاز به اجرای PEچندگانه روی یک پارامتر دارید، باید از چندین جمله استفاده کنید:
مترجم: ( بسط پارامتر )PE=Parameter Expansion

    $ file=$HOME/image.jpg; file=${file##*/}; echo "${file%.*}"
    image


  • عادت مفید:
    ممکن است برای ویرایش رشته‌ها، به استفاده از برنامه‌های خارجی از قبیل sed و awk و cut و perl یا سایر برنامه‌ها، وسوسه شوید. آگاه باشید که برای اجرای هر یک از این برنامه‌ها، یک پردازش اضافه‌ای باید شروع شود، که در بعضی موارد می‌تواند موجب کندی اجرا بشود. بسط پارامترها یک جایگزین بدون نقص است.




  • بسط پارامتر: هر گونه بسط(تعریف پیشتر را ملاحظه کنید) یک پارامتر. در حین انجام این بسط، عملیات معینی ممکن است روی کمیتی که بسط داده خواهد شد، صورت گیرد.