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

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

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

#!/bin/bash

پرسش و پاسخ شماره ۱۰۴

پرسش و پاسخ شماره ۱۰۴

چرا ‎ foo=bar echo "$foo"‎ رشته bar را چاپ نمی‌کند؟

این تله است، و باید به ترتیب دقیقی که، تفکیک کنندهBash هر مرحله را انجام می‌دهد، توجه شود.

بسیاری اشخاص وقتی ابتدا ترکیب ‎var=value command‎ را کشف می‌کنند و پی‌می‌برند که چطور در طول اجرای فرمان به طور موقتی متغیر را تنظیم می‌نماید، نهایتاً یک مثال مشابه این یکی می‌سازند و سردرگم می‌شوند که چرا آنچه را انتظار دارند انجام نمی‌دهد.

به عنوان یک توضیح:

$ unset foo
$ foo=bar echo "$foo"

$ echo "$foo"

$ foo=bar; echo "$foo"
bar

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

  • بسط پارامتر ‎$foo‎ اول انجام می‌شود. یک رشته تهی برای عبارت نقل‌قولی شده جایگزین می‌شود.

  • بعد از آن، Bash محیط موقتی را برقرار می‌کند و ‎foo=bar‎ را در آن قرار می‌دهد.

  • فرمان echo با یک رشته تهی به عنوان شناسه، و foo=bar در محیطش اجرا می‌شود. اما چون فرمان echo به متغیرهای محیط توجه ندارد، آن را نادیده می‌گیرد.

این نگارش آنطور که ما انتظار داریم عمل می‌کند:

$ unset -v foo
$ foo=bar bash -c 'echo "$foo"'
bar

در این حالت، مراحل زیر انجام می‌شوند:

  • یک محیط موقت همراه با ‎foo=bar‎ داخل آن، تنظیم می‌شود.

  • bash از داخل آن محیط فراخوانی می‌شود، و ‎-c‎ و ‎echo "$foo"‎ به عنوان دو شناسه‌اش به آن تحویل می‌شوند.

  • Bash پردازش فرزند ‎$foo‎ را با مقدار آن در محیط بسط می‌دهد و آن مقدار را تحویل echo می‌دهد.

در تمام حالت‌ها کاملاً واضح نیست که چرا اشخاص این سؤال را از ما می‌پرسند.اکثراً به نظر می‌رسد آنها به جای تلاش برای حل یک مشکل معین، درباره رفتار آن کنجکاو می‌باشند، بنابراین، من سعی نمی‌کنم مثالهایی در باره «روش صحیح انجام مواردی مانند این» تحویل بدهم، چون یک مشکل حقیقی برای حل کردن وجود ندارد.

موقعیت‌های ویژه‌ای در Bash وجود دارد که در آنها درک این مطلب می‌تواند مفید باشد. مثال زیر را ملاحظه کنید:

  arr=('Var 1' 'Var 2' 'Var 3' 'Var 4')

  #  ";" وصل کردن هر عنصر آرایه با‎
  #   نمودن unset سپس  و IFS تنظیم متغیر ‎:‎روش سنتی  ‎
  IFS=\;
  joinedVariable="${arr[*]}"
  unset -v IFS

‎  #  ‏به طور موقت تنظیم شود. eval برای مدت اجرای IFS  روش جایگزین، متغیر‎
  #  ‎4.3.0‎ در نگارش‌های کوچکتر از Bash راهکار نقل‌قول دوگانه یک باگ‎
  IFS=\; command eval 'JoinedVariable="${arr[*]}"'

در اینجا، پیشنهاد eval ساده‌تر و بیشتر برازنده است(در نظر شما! -- GreyCat). برای تضمین امنیت موقع به کارگیری eval باید دقت مناسب به عمل آید. پیشوند command برای تمام پوسته‌های غیر از Bash به اضافه Bash در حالت POSIX لازم است‎( http://wiki.bash-hackers.org/commands/builtin/eval#using_the_environment)‎ را ببینید. این مورد در نگارشهای اخیر zsh به سبب یک پسرفت آشکار، (رفتار مستند شده جهش به سوی ‎setopt POSIX_BUILTINS‎)، یا busybox به علت یک باگ که در این حالت تخصیص‌های محیط برای پخش شدن ناموفق می‌گردند، کار نخواهد کرد. (هر کس به اندازه کافی علاقمند است با خیال راحت باگ‌ها را اصلاح کند).


CategoryShell

پرسش و پاسخ 104 (آخرین ویرایش ‎2013-07-23 12:04:16‎ توسط GreyCat)