4. متغیرها- قسمت اول

دقیقاً مانند هر زبان برنامه‌نویسی موجود، مفهوم متغیرها - یک نام نمادین به محلی در حافظه است که می‌توانیم کمیت‌هایی را در آن‌جا ذخیره کنیم، بخوانیم و محتویات آن را دستکاری کنیم. پوسته بورن هم استثناء نیست، و دراین بخش کلیات آن ارائه می‌شود . در بخش متغیرها- قسمت دوم که به متغیرهایی که برای استفاده محیط تنظیم گردیده‌اند، نگاه می‌کنیم، بیشتر به آن پرداخته شده است
بیاید به عقب، به اولین مثال Hello World، نگاه کنیم. این مثال می‌تواند با استفاده از متغیرها اجرا شود (گرچه به اندازه‌ای ساده است که در حقیقت ضرورتی ندارد! )
توجه کنید که در اطراف علامت ‎ "=" ‎  فاصله‌ای نباید باشد: ‎VAR=value‎ کار می‌کند، اما ‎ VAR = value ‎  کار نمی‌کند . در حالت اول پوسته علامت ‎ "="‎ را می‌بیند وبه عنوان دستور واگذاری با آن رفتار می‌کند . درحالت دوم شل گمان می‌کند که کلمه VAR باید نام دستوری باشد که می‌باید آن را اجرا کند.
اگر در باره آن فکر کنید، قابل فهم است - به چه طریق دیگر می‌توانستید به شل بگویید که فرمان VAR را با‎ "=" ‎ به عنوان اولین شناسه و ‎ "value" ‎ به عنوان دومین شناسه، اجرا کند ؟
کد زیر را در فایل var1.sh وارد کنید :


var.sh
#!/bin/sh
MY_MESSAGE
="Hello World"
echo $MY_MESSAGE

این کد رشته ‎ "Hello World" ‎ را به متغیر MY_MESSAGE تخصیص می‌دهد و بعد دستور echo مقدار این متغیر را نمایش می‌دهد .
توجه کنید که به علامت‌های نقل‌قول در اطراف رشته Hello World احتیاج داریم . در حالیکه با دستور ‎ echo Hello World‎ می‌توانستیم آن‌ها را به کار نبریم، چون که echo هر تعداد پارامتر را می‌پذیرد، و یک متغیر فقط یک کمیت را ذخیره می‌کند، بنابراین یک رشته در بر دارنده کاراکتر فاصله باید نقل‌قولی بشود، تا پوسته بداند که با تمام آن به عنوان یک کمیت رفتار کند . در غیر این‌صورت شل پس از واگذاری ‎ MY_MESSAGE=Hello ‎  سعی می‌کند دستور World را اجراکند .

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

$ x="hello"
$ y
=`expr $x + 1`
expr: non-numeric argument
$

چون برنامه بیرونی expr فقط انتظار اعداد را دارد. لیکن بین آن دو تمایز دستور زبانی وجود ندارد :

MY_MESSAGE="Hello World"
MY_SHORT_MESSAGE
=hi
MY_NUMBER
=1
MY_PI
=3.142
MY_OTHER_PI
="3.142"
MY_MIXED
=123abc

توجه نمایید که، به هر حال، برای اجتناب از تفسیر ویژه توسط شل، کاراکترهای خاص باید به طور صحیح پوشانده شوند .
این مورد در بخش کاراکترهای گریز بیشتر بحث شده است.

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


var2.sh
#!/bin/sh
echo What is your name?
read MY_NAME
echo "Hello $MY_NAME - hope you're well."

Mario Bacinsky به طور دوستانه به من منعکس کرد که- من به طور معمول این علامت‌های نقل‌قول دوگانه در سطر سوم را از قلم می‌اندازم، که موجب پیغام خطایی به مضمون آن که علامت نقل‌قول تکی در کلمه ‎ "you're" ‎ تنها(بدون جفت) است، می‌گردد - این ازآن نوع مواردی است که می‌تواند یک برنامه‌نویس شل را کلافه کند، بنابراین مراقب این‌ها باشید!


این کاربرد دستور داخلی read شل است که از ورودی استاندارد یک سطر را می‌خواند، و در متغیر ارائه شده به آن، قرار می‌دهد .
توجه نمایید که اگر نام کامل خود را به آن بدهید، و حتی از علامت‌های نقل‌قول دوتایی در اطراف شناسه دستور echo نیز استفاده نکنید، هنوز هم خروجی شکل صحیحی دارد . چطور انجام شده است ؟ قبلاً برای تنظیم متغیر MY_MESSAGE ما باید از نقل‌قول دوگانه در اطراف آن استفاده می‌کردیم!
چیزی که اتفاق می‌افتد، آن است که دستور read به طور خودکار در اطراف ورودی‌اش نقل‌قول‌ها را قرار می‌دهد، بنابراین با فاصله‌ها به طور صحیح رفتار می‌شود . (البته در نمونه‌هایی همچون ‎ echo "$MY_MESSAGE" ‎ لازم است از نقل‌قول‌ها استفاده کنید).

محدوده متغیرها

در شل بورن، آنطور که درزبان‌هایی مثل C انجام می‌شود، نیازی به تعریف متغیرها نمی‌باشد، . اما اگر سعی کنید متغیر تعریف نشده‌ای را بخوانید، نتیجه یک رشته تهی است . هشدارهای خطا دریافت نمی‌کنید .
این مورد می‌تواند موجب باگ‌های ظریفی بشود- اگرشما واگذاری مقدار  ‎ MY_OBFUSCATED_VARIABLE=Hello ‎ را انجام داده وسپس دستور ‎ echo $MY_OSFUCATED_VARIABLE ‎  را اجرا کنید، هیچ چیز دریافت نمی‌کنید, ( به عنوان دومین نکته مبهم ) .

دستوری به نام export موجود است که در محدوده وجود متغیرها تأثیر اساسی دارد . برای اینکه به درستی بدانید با متغیرها چگونه رفتار می‌شود، لازم است، مواردی از چگونگی استفاده از این دستور را بفهمید .

اسکریپت کوچک myvar2.sh را ایجاد کنید:


myvar2.sh
#!/bin/sh
echo "MYVAR is: $MYVAR"
MYVAR
="hi there"
echo "MYVAR is: $MYVAR"

حالا اسکریپت را اجرا کنید:

$ ./myvar2.sh
MYVAR is
:
MYVAR is
: hi there

ابتدا هیچ کمیتی به MYVAR اختصاص نیافته، بنابراین تهی است. سپس مقداری به آن نسبت داده‌ایم، ونتیجه مورد انتظار نمایش داده می‌شود.
حالا به این صورت اجرا کنید:

$ MYVAR=hello
$
./myvar2.sh
MYVAR is
:
MYVAR is
: hi there

هنوزهم مقدار ندارد! چه بر سرش آمده است؟!
وقتی اسکریپت myvar2.sh را از شل محاوره‌ای فراخوانی می‌کنید، یک پوسته جدید برای اجرای اسکریپت تولیدمثل می‌کند. این به علت وجود سطر ‎ #!/bin/sh ‎  در ابتدای اسکریپت است، که قبلاً  بحث کردیم.
برای آن که یک متغیر به برنامه‌دیگری از جمله اسکریپت شل به ارث برسد، لازم است که آن را export نماییم. تایپ کنید:

$ export MYVAR
$
./myvar2.sh
MYVAR is
: hello
MYVAR is
: hi there

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

$ echo $MYVAR
hello
$

وقتی که اسکریپت پوسته خارج می‌شود، محیط آن هم نابود می‌شود. امامتغیر MYVAR مقدار اولیه hello در شل محاوره‌ای شما را در خود دارد.
به منظور دریافت تغییرات محیط از اسکریپت به شل محاوره‌ای، باید اسکربپت را source کنیم - این دستور در عوض تولید شل جدید برای اجرای اسکریپت، آن را به طور مؤثر در پوسته محاوره‌ای ما اجرا می‌کند.
می‌توانیم با دستور "." نیز اسکریپت را source نماییم:

$ MYVAR=hello
$
echo $MYVAR
hello
$
. ./myvar2.sh
MYVAR is
: hello
MYVAR is
: hi there
$
echo $MYVAR
hi there

تغییر ایجاد شده در متغییر، این مرتبه به شل ما سرایت کرده! این چگونگی کارکرد، به عنوان مثال، فایل ‎.profile‎ یا فایل‎ .bash_profile ‎ شما می‌باشد.
توجه کنید که در این حالت، اجرای ‎ export MYVAR‎ را لازم نداریم.
با تشکر از sway برای نشان دادن آن که، من ابتدا در کد بالا گفته بودم echo MYVAR نه آن طور که باید می‌بود echo $MYVAR . یک مورد با ارزش دیگر در باره متغیرها و قابل ذکر در این‌جا، ملاحظه نمودن اسکریپت زیر است:


#!/bin/sh
echo "What is your name?"
read USER_NAME
echo "Hello $USER_NAME"
echo "I will create you a file called $USER_NAME_file"
touch $USER_NAME_file

فکر کنید،چه نتیجه‌ای از آن انتظار دارید . به طور نمونه اگر "steve" را به عنوان USER_NAME، وارد کنید، اسکریپت باید فایل steve_file را ایجاد کند؟
در واقع، خیر. این موجب یک خطای عدم وجود متغیری به نام USER_NAME_file می‌گردد. شل نمی‌داند کجا نام متغیر تمام می‌شود و باقیمانده شروع می‌شود. چطور می‌توانیم این را مشخص کنیم؟
پاسخ این است، که ما خودِ متغیر را در ابروها محصور می‌کنیم :


user.sh
#!/bin/sh
echo "What is your name?"
read USER_NAME
echo "Hello $USER_NAME"
echo "I will create you a file called ${USER_NAME}_file"
touch "${USER_NAME}_file"

اکنون پوسته می‌داند که ما داریم به متغیر USER_NAME ارجاع می‌دهیم ومی‌خواهیم که پسوند ‎_file‎ به محتوای متغیر متصل گردد. چنین مواردی می‌تواند سقوط بسیاری از برنامه‌نویسان تازه وارد اسکریپت شل باشد، چرا که پیگردی سرچشمه معما می‌تواند دشوار باشد.

همچنین به علامت‌های نقل‌قول در اطراف ‎ "${USER_NAME}_file"‎ توجه نمایید - اگر کاربر ‎ "Steve Parker" ‎  را وارد کند (با درج فاصله )، سپس شناسه‌ها بدون نقل‌قول‌ها به دستور touch داده شوند، Steve و ‎Parker_file‎ خواهند بود - یعنی، در واقع مثل آن که گفته باشیم ‎ touch Steve Parker_file ‎، که دو فایل است که باید touch بشود، نه یک فایل. نقل‌قول‌ها باعث پرهیز از این امر می‌شوند. با تشکر از Chris به خاطر واضح نمودن این مورد.

Steve Parker  نوشته  Bourne و Bash راهنمای آموزشی اسکریپت نویسی
لطفاً برای بهتر دیدن صفحه از فایرفاکس استفاده کنید