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

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

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

#!/bin/bash

پرسش و پاسخ شماره ۵۳

پرسش و پاسخ شماره ۵۳

من یک اعلان فرمان تفننی رنگی دارم، اما حالا به نظر نمی‌رسد bash بداند پهنای ترمینال من چقدر است. سطرها به طور نادرستی شکسته می‌شوند.

شما باید ‎\[‎ و ‎\]‎ را در اطراف هر یک از رشته‌های escape غیرقابل چاپ در اعلان خود قرار بدهید. از این قرار:

fancy_prompt() {
  local blue=$(tput setaf 4)
  local purple=$(tput setaf 5)
  local reset=$(tput sgr0)
  PS1="\[$blue\]\h:\[$purple\]\w\[$reset\]\\$ "
}

بدون ‎\[ \]‎‏، bash گمان خواهد کرد بایت هایی که رشته‌های escape برای کُدهای رنگ را تشکیل می‌دهند به طور واقعی فضایی را در نمایشگر اشغال خواهند نمود، بنابراین bash قادر نخواهد بود بداند که اشاره‌گر واقعاً کجا می‌باشد.

اگر شما بازهم مشکل دارید، به عنوان مثال، موقعی که تاریخچه فرمانها را با کلیدهای جهتی بالا و پایین مرور می‌کنید، اطمینان حاصل نمایید که گزینه checkwinsize تنظیم باشد:

shopt -s checkwinsize

به فصلANSI escape codes ویکی پدیا مراجعه نمایید.

به طور کلی‌تر، شما باید از نوشتن رشته‌های escape ترمینال به طور مستقیم در اعلان خود اجتناب نمایید، زیرا آنها لزوماً در میان تمام ترمینال‌هایی که اکنون یا در آینده استفاده خواهید نمود قابل حمل نیستند. از tput برای تولید رشته‌های صحیح برای ترمینال خود استفاده کنید( این برنامه به بانک اطلاعاتی terminfo یا termcap شما نگاه می‌کند).

چون tput یک فرمان خارجی است، هر چند مرتبه که لازم باشد، شما باید آن را اجرا کنید، به این علت پیشنهاد می‌کنیم نتایج آن را در متغیرها ذخیره کنید، و (به جای استفاده از‎ $(tput ...)‎ به طور مستقیم در PS1، که در هر نوبتی که اعلان نمایش داده می‌شود tput را اجرا می‌کند)، آنها را در ساختار اعلان به کار ببرید. به این ترتیب کُد تشکیل دهنده اعلان برای خواندن آسانتر از خود اعلان می‌باشد، و درطیف متنوعی از ترمینال‌ها کار می‌کند. (بعضی ترمینال‌ها شاید ویژگی‌هایی که سعی می‌کنید به کار ببرید را نداشته باشند ، از قبیل رنگها، بنابراین نتایج در وضعیت‌های پیچیده به اندازه ‎ 100%‎ قابل حمل نیستند. اما می‌توانید نزدیک شوید.)


  • یادداشت شخصی: بازهم من این جواب را ترجیح می‌دهم:

    BLUE=$(tput setaf 4)
    PURPLE=$(tput setaf 5)
    RESET=$(tput sgr0)
    PS1='\[$BLUE\]\h:\[$PURPLE\]\w\[$RESET\]\$ '

    من درک می‌کنم که اشخاص می‌خواهند از مخدوش شدن متغیر namespace زیرنویس 1 اجتناب کنند، بنابراین از تابع و بخش local استفاده می‌کنند، که به ترتیب استفاده از نقل‌قول دوگانه و نیاز به دوتایی نمودن بعضی از \ها نه تمام آنها راتحمیل می‌کنند (و دانستن این که کدام یک -- اوه!). من پیچیدگی غیر ضروری آن را تشخیص می‌دهم. مسلماً، در صورتی‌که توسط کسی یا در جایی BLUE رونویسی شود، ریسک ناچیزی از تصادم وجود دارد، اما از طرف دیگر، راه حل نقل‌قول دوگانه نیز حامل این ریسک است که ترمینال دارای کاراکترهای \ در رشته‌های escape خود می‌باشد. و چون محتویات رشته‌های escape در نقل‌قولهای دوگانه تجزیه می‌شوند، اما در روش نقل‌قول منفرد تجزیه نمی‌شوند، چنین ترمینالی می‌تواند موارد بسیاری را آشفته کند. مثال تفاوت:

     imadev:~$ FOO='\w'; PS1='$FOO\$ '
     \w$ FOO='\w'; PS1="$FOO\\$ "
     ~$ 

    فرض کنیم ترمینال ما از ‎ \w‎ در یک رشته escape استفاده می‌کند. یک ‎\w‎ داخل متغیری که در PS1 نقل‌قولی شده منفرد رجوع می‌شود، وقتی اعلان چاپ گردد فقط به ‎ \w‎ لفظی بسط داده می‌شود، که آنچه ما می‌خواهیم است. اما در نگارش نقل‌فول دوگانه ، ‎\w‎ که به طور مستقیم داخل متغیر PS1 گمارده شده، موقع چاپ اعلان، توسط bash ارزیابی می‌شود. حال، من واقعاً ترمینالی را که از چنین نشانه‌ای استفاده ‌کند نمی‌شناسم --این یک ایراد کاملاً نظری است. اما از طرف دیگر، ایراد وارده به استفاده از متغیرهایی مانند BLUE نیز همینطور است. و به هر حال برخی اشخاص شاید واقعاً بخواهند در پوسته‌هایشان از ‎ echo "$BLUE"‎ استفاده کنند. بنابراین من نمی‌خواهم بگویم پاسخ نقل‌قول منفرد بهتر است، بلکه دوست داشتم ببینم که به عنوان یک جایگزین در اینجا حفظ می‌شود. -- GreyCat

    • کاملاً صحیح. من در ابتدا قصد داشتم فقط‎ BLACK= ‎ را به ‎RESET= ‎  تغییر بدهم(چون همه از سفید روی سیاه استفاده نمی‌کنند)، اما بعد اندیشیدم اگر اعلان به متغیرهایی که متغیر هستند وابسته نباشد، بهتر خواهد شد. من به طور واضح در مورد احتمال چنین رشته‌های escape ترمینال آگاه نبودم، بنابراین فکر می‌کنم ذکر کردن نگارش اول نقل‌قول منفرد، می‌توانست ایده بهتری باشد و همچنین یادآوری آنکه اگر آن متغیرها تغییر کنند چه اتفاقی می‌افتد.

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


پرسش و پاسخ 53 (آخرین ویرایش ‎ 2012-03-27 20:46:02 ‎ توسط GreyCat)


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