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

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

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

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

محیط

محیط

متغیرهای محیط

متغیرهای محیط باعث سردرگمی بسیاری هستند. عموماً اشخاص تصور می‌کنند «محیط» یک مخزن سراسری از تنظیمات برای سیستم گسترده است که پردازش‌ها در آن غوطه‌ور می‌شوند. این صحیح نیست.

به طور خلاصه:

متغیرهای محیط(نشان داده شده توسط env) همان پارامترهای Bash (نشان داده شده با set) نیستند. آنها سراسری نیستند (هر پردازش مجموعه خودش را دارد)، و آنها تنها وقتی پردازش فرزند تولید می‌شود از والد کپی می‌شوند. شما نمی‌توانید متغیرهای یک پردازش دیگر را تجدید نمایید. Bash به شما اجازه می‌دهد، رشته‌ها را به وسیله پیوند زدن یک پارامتر با همان نام به آن، با استفاده از فرمان export به متغیرهای محیط خودش تخصیص بدهید.

«محیط» چیست

محیط یک فضایی از حافظه برای هر پردازش است. وقتی پردازش یک پردازش جدید تولید‎(fork)‎ می‌کند، به طور کلی محیط انشعاب(fork) از محیط پردازش قدیمی کپی می‌شود. در نتیجه، پردازش جدید دارای یک محیط است که همانند، اما یک کپی از پردازش اصلی است.

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

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

مفهوم نیست. تشریح کنید!

نخست، بیایید مطمئن شویم که پارامترهای ‏Bash‏، ‎‎MY_ENV_VAR‎‎ و myParameter از قبل وجود ندارند. فرض که والد پوسته جاری متغیرهای نامبرده را در محیط خودش ندارد و شما هنوز آنها را ایجاد نکرده‌اید، این مرحله واقعاً ضروری نیست(آسیب نمی‌رساند). ما در خروجی، از برچسب "parent" برای علامت گذاری خروجی پوسته جاری، و از برچسب "child"برای علامت زدن خروجی تولید شده توسط یک پردازش فرزند استفاده می‌کنیم.

unset MY_ENV_VAR myParameter              # (حذف متغیرهایمان(همچنین از محیط‎‎
echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"   #  [parent] MY_ENV_VAR: چاپ می‌کند‎
echo "[parent] myParameter: $myParameter" #  [parent] myParameter: چاپ می‌کند‎

اکنون اجازه بدهید برخی متغیرها را ایجاد کنیم. این دستورات دو پارامتر Bash به نام ‎MY_ENV_VAR‎ و myParameter را ایجاد خواهند نمود، و آنوقت ‎MY_ENV_VAR‎ را به محیط Bash الحاق می‌کنند، که باعث ایجاد یک متغیر env با همان نام با محتوای منطبق، می‌گردد. ما فرمان ‎export myParameter‎ را به کار نمی‌بریم، به طوری که myParameter, صرفاً به عنوان یک پارامتر Bash وجود دارد. فرمان داخلی ‎declare -p‎ این را نمایش می‌دهد.

MY_ENV_VAR=Hello                          # را ایجاد می‌کند MY_ENV_VAR پارامتر‎
myParameter=Hello                         # را ایجاد می‌کند myParameter پارامتر
export MY_ENV_VAR                         # را به محیط الحاق می‌کند MY_ENV_VAR‎
echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"   # [parent] MY_ENV_VAR: Hello  چاپ می‌کند‎
echo "[parent] myParameter: $myParameter" # [parent] myParameter: Hello چاپ می‌کند‎
declare -p MY_ENV_VAR                     # declare -x MY_ENV_VAR="Hello"چاپ می‌کند
declare -p myParameter                    # declare -- myParameter="Hello"چاپ می‌کند‎

این است چگونگی بهنگام نمودن متغیر محیط خودمان. ما اساساً پارامترهای Bash را به هنگام کردیم. پارامتری که به محیط الحاق می‌شود باعث خواهد شد Bash متغیر محیط خود با همان نام را نیز به هنگام نماید (اگر متغیری از قبل export شده باشد، شما در حقیقت نیازی به export دوباره ندارید).

export MY_ENV_VAR=Bye
myParameter=Bye
echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"    # [parent] MY_ENV_VAR: Bye چاپ می‌کند‎
echo "[parent] myParameter: $myParameter"  # [parent] myParameter: Bye چاپ می‌کند‎

توجه کنید که این فرمانهای echo پارامترهای Bash ما را بسط می‌دهند، نه متغیرهای محیط را. این است چرای آنکه ما در نتیجه هر دو بسط، ولو اینکه تنها MY_ENV_VAR به یک متغیر محیط لینک می‌شود، "Bye" را می‌بینیم.

اجازه بدهید اکنون اثرات محیط را تشریح کنیم، موقعی که ما پردازش جدیدی ایجاد می‌کنیم، محیط را به داخل محیط پردازش جدید کپی می‌کنیم. محیط فقط MY_ENV_VAR را نگهداری می‌کند، نه myParameter (چون فقط آن را از قبل صادر کردیم). اینجا، یک پردازش جدید Bash ایجاد می‌کنیم که مقداری کد bash را که دوباره پارامترهای ما را بسط خواهد داد، اجرا می‌کند. پردازش جدید Bash متوجه شده است که محیطش شامل متغیری به نام MY_ENV_VAR می‌باشد، بنابراین یک پارامتر Bash با همان نام ایجاد نموده است. چون myParameter در محیط وجود ندارد، این پارامتر را ایجاد نکرده است، و آن را به تهی بسط می‌دهد.

bash -c 'echo "[child] MY_ENV_VAR: $MY_ENV_VAR"'   # [child] MY_ENV_VAR: Byeچاپ می‌کند‎
bash -c 'echo "[child] myParameter: $myParameter"' # [child] myParameter:چاپ می‌کند‎

پردازش فرزند ما فقط MY_ENV_VAR را دارد، اما در پوسته والد باز هم هر دو پارامتر را داریم.

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

echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"    # [parent] MY_ENV_VAR: Bye چاپ می‌کند‎
bash -c '
    echo "[child] MY_ENV_VAR: $MY_ENV_VAR" # [child] MY_ENV_VAR: Bye چاپ می‌کند‎
    MY_ENV_VAR="Hello again"               # فرزند را به هنگام می‌کند MY_ENV_VAR
    echo "[child] MY_ENV_VAR: $MY_ENV_VAR" # [child] MY_ENV_VAR: Hello again چاپ می‌کند‎
'
echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"    # [parent] MY_ENV_VAR: Bye چاپ می‌کند‎

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

echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"    # [parent] MY_ENV_VAR: Bye چاپ‎
bash -c '
    echo "[child] MY_ENV_VAR: $MY_ENV_VAR" # [child] MY_ENV_VAR: Bye چاپ‎
    sleep 5                                # (ثانیه توقف(تنظیم نسبت به سرعت تایپ‎5
    echo "[child] MY_ENV_VAR: $MY_ENV_VAR" # Prints: [child] MY_ENV_VAR: Bye
' &
MY_ENV_VAR="Hello again"                   # والد MY_ENV_VAR به هنگام نمودن‎
echo "[parent] MY_ENV_VAR: $MY_ENV_VAR"    # [parent] MY_ENV_VAR: Hello again چاپ‎

# :خروجی‎

[parent] MY_ENV_VAR: Bye
[child] MY_ENV_VAR: Bye
[parent] MY_ENV_VAR: Hello again
[child] MY_ENV_VAR: Bye

به طوری که می‌توانید ببینید،به هنگام کردن MY_ENV_VAR والد در حالیکه فرزند در انتظار بود، نسخه فرزند MY_ENV_VAR را تغییر نداده است.

اما پوسته‌های فرعی متفاوت هستند

یک پوسته فرعی یک پردازش فرزند است، و بنابراین محیط والدش را به ارث می‌برد، اما استثنایی است و پارامترهای معمولی والدش را نیز به ارث می‌برد.

$ unset myParameter
$ myParameter=42
$ (echo "$myParameter")
42
$ bash -c 'echo "$myParameter"'

$ 

به هر حال، باز هم پوسته فرعی نمی‌تواند پارامترهای والدش را تغییر بدهد، زیرا باز هم یک فرزند است.

$ myParameter=42
$ (myParameter=69)
$ echo "$myParameter"
42

محیط (آخرین ویرایش ‎2012-01-17 15:35:54‎ توسط GreyCat)