آموزش‌های خط فرمانی

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

آموزش‌های خط فرمانی

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

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



چطور می‌توانم تعیین نمایم که آیا یک متغیر شامل یک زیر رشته هست؟

در BASH:

  # Bash
  if [[ $foo = *bar* ]]

مورد فوق کمابیش در تمام نگارشهای Bash کار می‌کند. Bash نگارش 3 (و بالاتر) همچنین عبارتهای منظم را هم مجاز می‌داند:

  # Bash
  my_re='ab*c'
  if [[ $foo =~ $my_re ]]   # bash 3, matches abbbbcde, or ac, etc.

برای اشارات بیشتر در مورد دستکاری رشته‌ها در Bash، پرسش و پاسخ شماره 100 را ببینید.

اگر شما به جای Bash در BourneShell برنامه نویسی می‌کنید، ترکیب دستوری قابل حمل‌تر(اما نا زیباتری) وجود دارد:

  # Bourne
  case "$foo" in
    *bar*) .... ;;
  esac

case به شما اجازه می‌دهد متغیرها را در مقابل الگوهای globbingشکل (به انضمام globهای توسعه یافته) در صورتی که پوسته شما آنها را ارائه می‌کند،مطابقت دهید. اگر شما به روش قابل حمل برای مطابقت متغیرها در مقابل عبارات منظم نیاز دارید، از grep یا egrep استفاده کنید.

  # Bourne
  if echo "$foo" | grep bar >/dev/null 2>&1; then ...


CategoryShell

پرسش وپاسخ 41 (آخرین ویرایش ‎ 2010-11-29 22:24:01 ‎ توسط GreyCat)


دریافت ورودی به وسیله برنامه dialog


چگونه می‌توانم از dialog برای دریافت ورودی کاربر استفاده کنم؟

در اینجا یک نمونه هست:

  # POSIX
  foo=$(dialog --inputbox "text goes here" 8 40 2>&1 >/dev/tty)
  echo "The user typed '$foo'"

در اینجا تغییرمسیر قدری مهارت آمیز است.

  1. اول جمله ‎ foo=$(command)‎ برقرار شده، بنابراین خروجی استاندارد فرمان توسط bash ضبط می‌شود.

  2. داخل فرمان، قسمت ‎ 2>&1‎ باعث می‌شودخطای استاندارد به جایی فرستاده شود که خروجی استاندارد می‌رود-- به بیان دیگر اکنون stderr ضبط خواهد شد.

  3. بخش ‎>/dev/tty‎ خروجی استاندارد را به ترمینال ارسال می‌کند، بنابراین کادر محاوره‌ توسط کاربر دیده می‌شود. به هر حال باز هم خطای استاندارد ضبط خواهد شد.

یک سؤال رایج دیگر مرتبط با ‎dialog(1)‎، آن است که چگونه یک فرمان dialog پویایی شامل اقلامی که باید نقل‌قولی بشوند(یا به علت آنکه رشته‌های تهی هستند، یا به علت دارا بودن فضای سفید درون آنها)، تولید گردد. شخصی می‌تواند دستور eval را برای این مقصود به کار ببرد، اما پاکیزه‌ترین روش برای رسیدن به این هدف استفاده ازیک آرایه است.

  # Bash
  unset m; i=0
  words=(apple banana cherry "dog droppings")
  for w in "${words[@]}"; do
    m[i++]=$w; m[i++]=""
  done
  dialog --menu "Which one?" 12 70 9 "${m[@]}"

در این مثال، حلقه while که آرایه m را دارای عضو می‌کند، می‌توانست از لوله، فایل، و غیره خوانده بشود.

به یاد بیاورید که ساختار ‎ "${m[@]}"‎ به تمام محتویات یک آرایه بسط می‌یابد، اما با هر عضو صریحاً نقل‌قول شده. این با ساختار ‎"$@"‎ برای اداره پارامترهای مکانی قابل قیاس است. برای توضیحات بیشتر پرسش و پاسخ شماره 50 را ببینید.

نگارشهای bash جدیدتر دارای ترکیب دستوری به طور جزئی شکیل‌تری برای افزودن عناصر به یک آرایه می‌باشند:

  #  و بالاتر Bash 3.1 نگارش
  ...
  for w in "${words[@]}"; do
    m+=("$w" "")
  done
  ...

این هم مثال دیگری با استفاده از نام فایلها:

  # Bash
  files=(*.mp3)       # .اینها می‌توانند شامل فاصله‌ها، علامت آپاستروف و غیره باشند
  cmd=(dialog --menu "Select one:" 22 76 16)
  i=0 n=${#cmd[*]}
  for f in "${files[@]}"; do
      cmd[n++]=$((i++)); cmd[n++]="$f"
  done
  choice=$("${cmd[@]}" 2>&1 >/dev/tty)
  echo "Here's the file you chose:"
  ls -ld -- "${files[choice]}"

یک عمل مستقل از این پرسش اما مفید dialog، پیگردی نمودن پیشرفت پردازشی است که خروجی را تهیه می‌کند. در این پایین مثالی هست که از dialog برای پیگردی پردازشهای نوشتن در فایل ثبت وقایع، استفاده می‌کند. در پنجره dialog، یک کادر تعقیب که خروجی در آن نگهداری می‌شود و یک کادر پیغام با کلید quit قابل کلیک وجود دارد. کلیک روی کلید quit باعث اجرای trap ، حذف tempfile، و تخریب پردازش تعقیب می‌گردد.

  # POSIX(?)
  # نمی‌توانید فایلی که وجود ندارد را تعقیب کنید بنابراین  ‎
  #                   همیشه از وجود آن از قبل مطمئن شوید‎
  rm -f dialog-tail.log; echo Initialize log >> dialog-tail.log
  date >> dialog-tail.log
  tempfile=`tempfile 2>/dev/null` || tempfile=/tmp/test$$
  trap 'rm -f $tempfile; stty sane; exit 1' 1 2 3 15
  dialog --title "TAIL BOXES" \
        --begin 10 10 --tailboxbg dialog-tail.log 8 58 \
        --and-widget \
        --begin 3 10 --msgbox "Press OK " 5 30 \
        2>$tempfile &
  mypid=$!
  for i in 1 2 3;  do echo $i >> dialog-tail.log; sleep 1; done
  echo Done. >> dialog-tail.log
  wait $mypid
  rm -f $tempfile

برای یک مثال از ایجاد نوار پیشرفت با استفاده از ‎ dialog --gauge‎, پرسش و پاسخ شماره 44 را ببینید.


CategoryShell

پرسش و پاسخ 40 (آخرین ویرایش ‎ 2011-01-18 18:55:21 ‎ توسط GreyCat)


فایلهای نقطه‌ای


تمام فایلهای نقطه‌ای که bash می‌خواند کدام هستند؟

صفحه فایلهای نقطه‌ای را ملاحظه کنید


فایلهای نقطه‌ای(DotFiles)

پیکربندی نشست‌های login شما با فایلهای نقطه‌ای

این نوشته فرض می‌کند شما در حال استفاده از bash به عنوان پوسته نشست login خود هستید و از لینوکس استفاده می‌کنید، مگر اینکه طور دیگری تصریح شده باشد.

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

اتصال‌های کنسول

بیایید با ساده‌ترین پیکربندی شروع کنیم: یک اتصال محلی در کنسول متنی لینوکس، ابداً بدون هرگونه محیط گرافیکی. در این حالت، موقعی که کامپیوتر را راه‌اندازی می‌کنید، شما سرانجام یک اعلان ‎"login:"‎ مشاهده می‌کنید. این اعلان توسط برنامه‌ای به نام ‎getty(8)‎ تولید می‌گردد که روی دستگاه tty (ترمینال) اجرا می‌شود. وقتی شما یک نام کاربری را تایپ می‌کنید، getty آن را می‌خواند و به برنامه‌ای به نام ‎login(1)‎ عبور می‌دهد. برنامه login بانک اطلاعات کلمه عبور را می‌خواند و تصمیم می‌گیرد که آیا از شما یک کلمه عبور درخواست کند.وقتی شما کلمه عبور خود را تأمین کرده‌اید، login پوسته لاگین شما، bash را‎exec(2)‎ می‌کند.

اکنون، چون bash به عنوان یک پوسته لاگین دارد فراخوانی می‌شود(با نام ‎"-bash"‎، یک ترفند ویژه قدیمی)، اول فایل ‎/etc/profile‎ را می‌خواند. سپس به دایرکتوری خانگی برای یافتن ‎.bash_profile‎ نگاه می‌کند، و اگر آن را پیدا کند، می‌خواند. اگر فایل ‎.bash_profile‎ را پیدا نکند، برای ‎.bash_login‎ جستجو می‌کند، و اگر آنرا پیدا نکند، فایل ‎.profile‎ (فایل پیکربندی استاندارد پوسته بورن و Korn)را جستجو می‌کند. در غیر اینصورت، جستجو برای فایلهای نقطه‌ای را متوقف می‌کند، و اعلان فرمان را به شما می‌دهد.

بسیاری از سیستم‌های لینوکس دارای یک لایه دیگری به نام زیرنویس PAM هستند که مربوط به اینجا می‌باشد. قبل از اجرای bash، برنامه login فایل ‎/etc/pam.d/login‎ (یا معادل آن در سیستم شما) را خواهد خواند، که شاید به او بگوید فایلهای مختلف دیگری از قبیل ‎/etc/environment‎ را بخواند. سیستم‌های دیگر از قبیل OpenBSD دارای یک فایل ‎/etc/login.conf‎ هستند که محدودیت‌های منابع برای کلاس‌های مختلف حسابهای کاربری را کنترل می‌کند. بنابراین ممکن است، قبل از اینکه پوسته شما ‎/etc/profile‎ را بخواند، شما دارای متغیرهای اضافی محیط، محدودیت‌های پردازش، و غیره، باشید.

ممکن است شما توجه نموده باشید که در این وضعیت فایل ‎.bashrc‎ خوانده نمی‌شود. بنابراین شما همواره باید سطر ‎source ~/.bashrc‎ را در انتهای فایل ‎.bash_profile‎ خود، به منظور تحمیل خوانده شدن آن به وسیله پوسته لاگین داشته باشید.

پس چرا ‎.bashrc‎ یک فایل مجزا از ‎.bash_profile‎ است؟ دو دلیل وجود دارد. اول به دلیل کارایی است -- زمانی که ماشین‌ها در مقایسه با ایستگاه‌های کاری امروزی بیش از حد آهسته بودند، پردازش فرمانهای ‎.profile‎ یا ‎.bash_profile‎ می‌توانست واقعاً زمان طولانی را صرف کند، مخصوصاً روی ماشین‌هایی که در آنها باید کار بسیاری توسط فرمانهای خارجی انجام می‌گردید(قبل از پوسته‌های Korn وBash ). بنابراین دستورات برپاسازی سخت‌گیر اولیه، که متغیرهای محیط که می‌توانند به پردازشهای فرزند عبور داده شوند، را تولید می‌نمودند در ‎.bash_profile‎ قرار داده می‌شوند. تنظیمات موقتی، مستعارها یا توابع که به ارث نمی‌رسند در ‎.bashrc‎ قرار داده می‌شوند به طوری که می‌توانند توسط هر پوسته فرعی بازخوانی بشوند.

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


اجازه بدهید مرور کنیم. یک مدیر سیستم، یک سیستم دبیان(که مبتنی بر لینوکس است و از PAM استفاده می‌کند) تنظیم نموده و یک تنظیم منطقهLANG=en_US‎ در ‎/etc/environment‎ دارد. یک کاربر محلی به نام pierre ترجیح می‌دهد به جای آن از تنظیم منطقه ‎fr_CA‎ استفاده کند، از این جهت او سطر ‎export LANG=fr_CA‎ را در فایل ‎.bash_profile‎ خود قرار می‌دهد. او همچنین سطر ‎source ~/.bashrc‎ را در همان فایل می‌گذارد، و سپس ‎set +o histexpand‎ را در فایل ‎.bashrc‎ خودش قرار می‌دهد. اکنون از طریق کنسول به این سیستم دبیان متصل می‌شود. ‎login(1)‎ (از طریق PAM) فایل ‎/etc/environment‎ را می‌خواند و ‎LANG=en_US‎ را در محیط قرار می‌دهد. سپس login پوسته bash را اجرا می‌کند، که فایل ‎/etc/profile‎ و ‎.bash_profile‎ را می‌خواند. فرمان export در فایل ‎.bash_profile‎ موجب می‌گردد متغیر محیط ‎LANG‎ از ‎en_US‎ به ‎fr_CA‎ تغییر کند. عاقبت، فرمان source باعث می‌شود bash فایل ‎.bashrc‎ را بخواند، به طوری که فرمان ‎set +o histexpand‎ برای این پوسته اجرا می‌شود. بعد از تمام اینها، pierre اعلان فرمان خود را به دست می‌آورد و آماده تایپ دستورات به صورت محاوره‌ای می‌باشد.

اتصال‌های راه دور پوسته

حالا اجازه بدهید به دومین مثال ساده بپردازیم: یک لاگین ssh. این مورد بسیار مشابه اتصال از طریق کنسول متنی می‌باشد، به استثنای آن که به جای استفاده از برنامه getty و login برای اداره خوش‌آمد گویی اولیه و تصدیق اعتبار کلمه عبور، برنامه ‎sshd(8)‎ آن را اداره می‌کند. sshd در دبیان به PAM نیز پیوند شده، و فایل ‎/etc/pam.d/ssh‎ را(به جای ‎/etc/pam.d/login‎) خواهد خواند. و گر نه، اداره کردن همانطور است. وقتی که sshd به سرعت مراحل PAM را طی کرده است( اگر در سیستم شما قابل اجرا باشد)، bash را به عنوان پوسته لاگین اجرا می‌کند، که باعث خواندن ‎/etc/profile‎ و سپس یکی از فایلهای ‎.bash_profile‎ یا ‎.bash_login‎ یا ‎.profile‎ می‌گردد.

تفاوت اصل موقعی که یک پوسته لاگین راه دور به جای لاگین کنسول محلی استفاده می‌کنید آن است که، یک پردازش سرویس‌گیرنده ssh در سیستم محلی شما( یا هر جایی که شما از آن ssh نموده‌اید) در حال اجرا است که متغیرهای محیط خودش را از قبل دارد -- و شاید برخی از آنها به sshd روی سیستمی که شما در حال اتصال به آن هستید، فرستاده شده باشند. مخصوصاً، برای متغیرهای ‎LANG‎ و ‎LC_*‎ مطلوب است توسط پوسته راه دور محافظت بشوند. متأسفانه، فایلهای پیکربندی روی سرویس‌دهنده ممکن است آنها را باطل کنند. به دست آوردن این تنظیم برای کار کردن صحیح در تمام وضعیت‌ها مهارت‌آمیز است. (این یک نمونه فرایند برای دبیان است.)

پوسته‌های راه دور غیر لاگین غیر محاوره‌ای

Bash دارای یک گزینه ویژه زمان کامپایل می‌باشد که باعث خواهد شد در نشست‌های ssh غیر محاوره‌ای بدون لاگین فایل ‎.bashrc‎ منبع بشود(مترجم: یعنی آن را بخواند و در محیط جاری اجرا کند.). این ویژگی فقط توسط برخی ازفروشندگان سیستم‌عامل فعال می‌شود (اکثر توزیع کنندگان لینوکس). این گزینه در یک Bash ساخته شده پیشفرض نگهدارنده اصلی فعال نیست، و (بر اساس تجربه) در OpenBSD هم نیست.

اگر این ویژگی روی سیستم شما فعال شده باشد، Bash تشخیص می‌دهد که SSH_CLIENT یا SSH_CLIENT2 در محیط است و در این حالت فایل ‎.bashrc‎ را منبع می‌کند. برای مثال فرض کنید شما سطر ‎var=foo‎ را در فایل ‎.bashrc‎ راه دور خود دارید و این را ‎ssh remotehost echo \$var‎ را انجام می‌دهید، foo را چاپ خواهد نمود.

این پوسته غیر محاوره‌ای است، بنابراین اگر شما نمی‌خواهید موارد ‎.bashrc‎ به این طریق اجرا بشوند می‌توانید ‎$-‎ یا ‎$PS1‎ را بررسی کنید.

بدون این گزینه bash بررسی خواهد نمود که اگر stdin به یک سوکت وصل شده است در این حالت نیز ‎.bashrc‎ را منبع می‌کند، اما اگر شما از یک سرویس‌دهنده openssh جدید‎(>5.0)‎ استفاده کنید این بررسی ناموفق می‌شود، که احتمالاً شما این مورد را فقط درسیستم‌های قدیمی‌تر مشاهده می‌کنید.

توجه نمایید که یک بررسی روی SHLVL نیز انجام می‌شود، بنابراین اگر ‎ssh remotehost bash -c echo‎ را انجام بدهید، آنوقت اولین bash فایل ‎.bashrc‎ را منبع می‌کند، اما دومی خیر(آن bash صریح در سطر فرمان که echo را اجرا می‌کند).


نشست‌های X

بیایید فرض کنیم pierre (کاربر کنسول ما) تصمیم می‌گیرد که برای مدتی X را راه‌اندای کند. او startx را تایپ می‌کند، که هر یک از مجموعه سرویس گیرنده‌های X که او می‌پسندد را فراخوانی می‌کند. startx یک روکش پیرامون xinit است، که سرویس‌دهنده X را راه‌اندازی می‌کند، و سپس به سرعت فایل ‎.xinitrc‎ یا ‎.xsession‎ (هر یک که موجود باشد) کاربر pierre، یا در غیر اینصورت Xsession پیش‌فرض عمومی سیستم را مرور می‌کند. اجازه بدهید فرض کنیم pierre دارای فرمان ‎exec fluxbox‎ (و هیچ چیز دیگر) در این فایل ‎.xsession‎ می‌باشد. وقتی سیاهی از بین می‌رود، او یک پردازش در حال اجرای سرویس‌دهنده X (به عنوان root)، و یک پردازش fluxbox (به عنوان pierre) دارد. fluxbox به عنوان فرزند xinit ایجاد شده، که فرزند startx بود، که یک فرزند bash بود، چنانکه ‎LANG pierre‎ و سایر متغیرهای محیط را ارث می‌برد. موقعی که pierre موردی را از منوی مدیر پنجره راه‌اندازی می‌کند، آن فرمان جدید یک فرزند fluxbox خواهد بود، چنانکه به همان اندازه LANG، PATH، MAIL، وغیره را ارث می‌برد. علاوه بر تمام آنها، fluxbox متغیر محیط DISPLAY را که به او می‌گوید کدام سرویس‌دهنده X متصل است را به ارث می‌برد(در این حالت، احتمالاً ‎:0‎).

پس موقعی که pierre یک xterm را اجرا می‌کند، چه رخ می‌دهد؟ fluxbox یک پردازش xterm را "fork" و "exec" می‌کند، که DISPLAY ومانند آن را ارث می‌برد. xterm به سرویس‌دهنده X متصل می‌شود، اگر لازم باشد اعتبارسنجی می‌شود، و سپس خودش را در نمایشگر رسم می‌کند. علاوه بر DISPLAY، از متغیر SHELL کاربر pierre که احتمالاً شامل ‎/bin/bash‎ است ارث می‌برد، بنابراین یک شِبه-ترمینال برقرار می‌کند، و آنوقت یک پردازش ‎/bin/bash‎ برای اجرا در آن تولید می‌کند. چون ‎/bin/bash‎ با یک - شروع نشده است، یک پوسته لاگین نخواهد بود.یک پوسته معمولی خواهد بود که فایل ‎/etc/profile‎ یا ‎.bash_profile‎ یا ‎.profile‎ را نخواهد خواند. به جای آن،فایل ‎.bashrc‎ که در مثال ما محتوی سطر ‎set +o histexpand‎ می‌باشد را می‌خواند. بنابراین xterm جدید او در حال اجرای یک پوشته bash، با تمام مجموعه متغیرهای محیط او می‌باشد(به خاطر بیاورید، آنها از پوسته لاگین کنسول متنی اولیه او به ارث رسیده‌اند)، و گزینش انتخابی پوسته‌اش فعال شده است(از فایل ‎.bashrc‎).

آنچه تا اینجا دیده‌ایم، تنظیم عادی یونیکس است. بسیاری اشخاص راه‌اندازی سیستم‌هایشان به این طریق را انتخاب می‌کنند، و به خوبی کار می‌کند. همچنین یک دفعه که مفاهیم اصلی را نشان داده باشید، به طور مساعدی برای فهمیدن ساده است. اگر بخواهید موردی را تغییر بدهید، به طور دقیق می‌دانید کدام فایل را برای تحقق آن ویرایش کنید -- مستعارها و گزینه‌های موقتی پوسته در ‎.bashrc‎، و برای متغیرهای محیط، محدودیت‌های فرایند، و مانند آن فایل ‎.bash_profile را ویرایش کنید‎. اگر می‌خواهید قبل از اینکه مدیر پنجره یا محیط میز کارتان فراخوانی بشود، فرمانهای مختلف سرویس‌گیرنده X اجرا بشود( به عنوان مثال، ‎xterm &‎ یا ‎xmodmap -e 'keysym Super_R = Multi_key'‎)، می‌توانید آنها را درفایل ‎.xsession‎ قبل از سطر ‎exec YourWindowManager‎ قرار بدهید.

به هر حال بعضی اشخاص دوست دارند یک لاگین گرافیکی(مدیر نمایش) داشته باشند، و این هر چیزی را که تا اینجا دیده‌ایم تغییر می‌دهد. به جای getty و login، یک پردازش اداره اعتبارسنجی xdm (یا gdm یا kdm یا wdm یا ...) وجو دارد. و بزرگترین تفاوت همگی آن است که وقتی پردازش ‎*dm‎ ما اعتبار سنجی کاربر را به پایان می‌رساند، یک پوسته لاگین "exec" نمی‌کند. به جای آن، مستقیماً یک نشست X را "exec" می‌کند. بنابراین، ابداً هیچ کدام از فایلهای پیکربندی کاربر خوانده نمی‌شوند -- نه ‎/etc/profile‎، نه ‎.bash_profile‎ و نه ‎.profile‎. (اما ‎/etc/environment‎ باز هم بواسطه PAM خواند می‌شود، ‎/etc/pam.d/*dm‎ برای به کار بردن محدودیت‌های pam پیکربندی می‌شود، حالتی که در دبیان است.)

اجازه بدهید xdm را به عنوان یک مثال در نظر بگیریم. Pierre یک روز بعد از مرخصی باز می‌گردد و پی می‌برد مدیر سیستم او xdm را روی سیستم دبیان نصب کرده است. او خیلی خوب به سیستم متصل می‌شود و xdm فایل ‎.xsession‎ او را می‌خواند و fluxbox را اجرا می‌کند.به نظر می‌رسد همه چیز درست است تا آنکه یک پیغام خطا با زبان منطقه اشتباه دریافت می‌کند! چون متغیر ‎LANG‎ در فایل ‎.bash_profile‎ او باطل می‌شود، و از آنجایی کهxdm هرگز فایل ‎.bash_profile‎ را نمی‌خواند، متغیر LANG او اکنون به جای ‎fr_CA‎ به ‎en_US‎ تنظیم گردید است.

حال، راه حل خام برای این مشکل آن است که به جای راه‌اندازی ‎xterm‎، او می‌تواند مدیر پنجره خود را برای راه‌اندازی ‎xterm -ls‎ پیکربندی نماید. این نشانه به xterm می‌گوید که به جای راه‌اندازی یک پوسته معمولی، باید یک پوسته لاگین اجرا کند. تحت این تنظیم، xterm یک ‎/bin/bash‎ تولید می‌کند، اما ‎-/bin/bash‎ (یا شاید ‎-bash‎) را در حامل شناسه می‌گذارد، چنانکه bash مانند یک پوسته لاگین عمل می‌کند. این به معنای آن است که هر دفعه که او xterm جدیدی باز می‌کند، فایل ‎/etc/profile‎ و ‎.bash_profile‎ را خواهد خواند(رفتار داخلی bash ) ، و سپس ‎.bashrc‎ را (زیرافایل ‎.bash_profile‎ او می‌گوید که این کار را انجام بدهد). ممکن است ابتدا به نظر برسد که این مورد به خوبی کار می‌کند -- فایلهای نقطه‌ای او سنگین نیستند، بنابراین هرگز متوجه تأخیر نمی‌شود -- اما مسئله محیل‌تری وجود دارد. او همچنین یک مرورگر وب را مستقیماً از منوی fluxbox اجرا می‌کند، و مرورگرش متغیر LANG را از fluxbox ارث می‌برد، که بازهم به منطقه اشتباه تنظیم می‌باشد. بنابراین در حالیکه شاید xterm هایش خوب باشند، و هر موردی که از xterm هایش راه‌اندازی شود ممکن است خوب باشد، مرورگر وب بازهم صفحه‌ها را با زبان منطقه‌ اشتباه به او می‌دهد.

بنابراین، بهترین راه حل برای این مشکل چیست؟ واقعاً یک راه حل همگانی وجود ندارد. یک راهکار ویرایش فایل ‎.xsession‎ به موردی مانند این است:

[ -r /etc/profile ] && source /etc/profile
[ -r ~/.bash_profile ] && source ~/.bash_profile
xmodmap -e 'keysym Super_R = Multi_key'
xterm &
exec fluxbox

این باعث می‌شود پوسته‌ای که اسکریپت ‎.xsession‎ را تفسیر می‌کند، اگر فایلهای ‎/etc/profile‎ و ‎.bash_profile‎ موجود و قابل خواندن باشند، قبل از اجرای xmodmap یا xterm یا اجرای مدیر پنجره، آنها را بخواند. به هر حال، یک اشکال بالقوه در این راهکار وجود دارد: تحت xdm، پوسته‌ای که ‎.xsession‎ را می‌خواند بدون یک کنترل ترمینال اجرا می‌شود. اگر یکی از فایلهای ‎/etc/profile‎ یا ‎.bash_profile‎ هر فرمانی را استفاده نماید که وجود یک ترمینال را فرض می‌کند(از قبیل fortune یا stty)، آن فرمان ممکن است ناموفق گردد. این است دلیل اصلی آنکه چرا xdm به طور پیش‌فرض آن فایلها را نمی‌خواند. اگر تصمیم دارید از این راهکار استفاده کنید، باید مطمئن شوید که تمام فرمانها در فایلهای نقطه‌ای شما، وقتی ترمینال وجود ندارد مصون می‌باشند.

یک روش برای انجام آن، اما بازهم از دست ندادن آن فرمانها برای استفاده موقعی که با ssh لاگین می‌کنید،محافظت ازبلوکهای مناسب کد با یک جمله if است. برای مثال:

## Sample .bash_profile
export PATH=$HOME/bin:$PATH
export MAIL=$HOME/Maildir/
export LESS=-X
export EDITOR=vim VISUAL=vim
export LANG=fr_CA
# Begin protected block
if [ -t 0 ]; then       # check for a terminal
  [ x"$TERM" = x"wy30" ] && stty erase ^h       # sample legacy environment
  echo "Welcome to Debian, $LOGNAME"
  /usr/games/fortune
fi
# End protected block
[ -r ~/.bashrc ] && source ~/.bashrc

متأسفانه، سایر برنامه‌های مدیر نمایش (kdm، gdm، و غیره) همگی همان فایلهای پیکربندی را به کار نمی‌برند که xdm استفاده می‌کند. بنابراین شاید این رویکرد برای آنها کار نکند. ممکن است لازم باشد شما مستندات برنامه مدیر نمایش خود را کنکاش کنید، که پی ببرید کدام فایلها را باید برای کنترل نشست‌های خود استفاده کنید.


CategoryUnix

فایلهای نقطه‌ای (آخرین ویرایش ‎2011-04-21 19:06:11‎ توسط ppp-94-64-90-90)


  1. مترجم: Pluggable Authentication Modules: مدول‌های تصدیق اعتبار قابل تعویض کاربر برای امنیت سیستم. یک مجموعه کتابخانه‌های مشترک که تعین می‌کند کاربر چگونه اعتبار سنجی خواهد شد، به عنوان مثال، مطابق قرارداد یونیکس کاربران پس از تایپ نام کاربری خود در اعلان login با عرضه نمودن یک کلمه عبور در اعلان password خودشان را تصدیق اعتبار می‌کنند. در بسیاری از رویدادها از قبیل دسترسی داخلی به یک ایستگاه کاری این شکل اعتبار سنجی کافی در نظر گرفته شده است. در سایر حالت‌ها اطلاعات بیشتری لازم می‌شود. اگر کاربری از یک منبع خارجی مانند اینترنت به سیستم داخلی متصل گردد، ممکن است اطلاعات بیشتر یا متناوبی لازم بشود، شاید یک کلمه عبور یکبار مصرف. PAM اینگونه توانایی و خیلی بیشتر را فراهم می‌کند. مهمتر از همه مدول‌های pam به شما اجازه می‌دهند محیط خود را برای سطوح مختلف امنیتی پیکربندی کنید. (بازگشت)


Unix Permissions


مجوزهای فایل در یونیکس چگونه کار می‌کنند؟

مجوزها را ملاحظه کنید.


مجوزهای یونیکس

هر فایل در درون یک فایل سیستم یونیکس -- و این(فایل) هر چیزی را که می‌تواند در سیستم فایل یونیکس باشد، شامل می‌شود: فایلها، دایرکتوریها، لوله‌های بانام، سوکت‌ها، دستگاههای بلوکی و کاراکتری، و پیوندهای نمادین -- دارای یک مالک، گروه، و مجموعه‌ای از مجوزها می‌باشد.

در اصلی‌ترین سطح، مجوزهای یک فایل به این طریق عمل می‌کنند:

griffon:~$ ls -l .bashrc

-rw-r--r--  1 greg greg 856 2004-09-06 15:26 .bashrc
^\_/\_/\_/
| |  |  |
| |  |  +----- سه کاراکتر انتهایی مجوزهای تمام کاربران دیگر را نشان می‌دهد‎
| |  |
| |  +-------- سه کاراکتر بعدی مجوزهای گروه فایل را نشان می‌دهد‎
| |
| +----------- سه کاراکتر اول مجوزهای مالک فایل را نشان می‌دهد‎
|
+------------- خط تیره در ابتدا یعنی یک فایل معمولی است‎

این فایل ‎.bashrc‎ مالکی به نام ‎"greg"‎ وگروه ‎"greg"‎ دارد، اندازه آن 856 بایت است، آخرین ویرایش آن به تاریخ ‎2004-09-06‎ ساعت ‎15:26‎ بوده، و دارای یک پیوند(همان که ما در حال دیدنش هستیم) می‌باشد. یک فایل معمولی است(کاراکتر خط تیره- در ستون اول)، دارای مجوز ‎"rw-"‎(خواندن و نوشتن اما اجرا خیر) برای مالک می‌باشد، دارای مجوز ‎"r--"‎ (خواندن، اما نوشتن و اجرا خیر) برای گروهش، و مجوز ‎"r--"‎(فقط خواندنی) برای سایر کاربران سیستم است.

این دیدگاهی سطحی است. در حقیقت فایلها در مالکیت نامهایی مانند "greg" نیستند. آنها توسط شماره UID (شماره شناسایی کاربر) به تملک در می‌آیند، و ‎ls(1)‎ آن شماره شناسایی‌های کاربری‏(UID) را از طریق فراخوان‌های کتابخانه استاندارد C از قبیل ‎getpwuid(3)‎ به نامهای قابل خواندن انسان، مانند ‎"greg"‎ ارتباط می‌دهد. در مثال نشان داده شده فوق، ‎"greg"‎ به طور محلی در فایل ‎/etc/passwd‎ تعریف می‌شود، و موقعی که فرمانls با گزینه ‎-l‎ اجرا می‌شود، فایل passwd را سطر به سطر می‌خواند تا سطری با UID مالک فایل در فیلد سوم را پیدا کند. همچنین، فایلها در حقیقت با نام به گروه تعلق نمی‌گیرند، آنها با شماره GID(شماره شناسایی گروه) به گروه تعلق می‌گیرند، و ls نام متناظر با آن را از بانک اطلاعات گروه سیستم که به طور نوعی ‎/etc/group‎ است، بیرون می‌کشد. نامهای کاربر و گروه همچنین می‌تواند از NIS، LDAP، یا سایر بانکهای اطلاعاتی اخذ گردد، اما این موضوع خارج از حوزه این مقاله می‌باشد. نکته آنست که در حقیقت همه چیز در باب اعداد است.

این هم همان فایل بدون تبدیل «عدد به نام»:

griffon:~$ ls -ln .bashrc
-rw-r--r--  1 1000 1000 856 2004-09-06 15:26 .bashrc

کاربر "greg" در واقع شماره 1000 است، و گروه "greg" نیز شماره 1000 است. گزینه ‎-n‎ تبدیل معمول اعداد به نامها را موقوف می‌کند.

به همین نحو،واقعاً محلی در سیستم فایل وجود ندارد که در آنجا رشته ‎"rw-r--r--"‎ برای این فایل ذخیره بشود. این درست روش قابل خواندن انسانی ls است برای نمایش اعدادی که مجوزهای فایل را ذخیره می‌کنند. حال بیایید نگاه نزدیکتری به این قسمت داشته باشیم.

هر کاراکتر در رشته ‎"rw-r--r--"‎ یا یک حرف است یا خط تیره. اگر ما مجوز اجرا را (با ‎chmod +x .bashrc‎) اضافه می‌کردیم، آنوقت فایل این طور دیده می‌شد:

griffon:~$ chmod +x .bashrc; ls -l .bashrc
-rwxr-xr-x  1 greg greg 856 2004-09-06 15:26 .bashrc*

کاراکتر * در انتها به علت این واقعیت است که در حقیقت ls یک مستعار یا تابع پوسته است که گزینه ‎-F‎ را به ‎/bin/ls‎ اضافه می‌کند(مترجم: در سیستم شما می‌تواند اینطور نباشد). می‌توانید فعلاً از آن صرفنظر کنید.

موقعی که مجوز اجرا را اضافه می‌کنیم، رشته جدید ‎"rwxr-xr-x"‎ برای مجوزهای فایل نمایش داده می‌شود. به طوری که شاید حدس بزنید، این رشته یعنی ما دارای مجوز ‎"rwx"‎ (خواندن، نوشتن و اجرا)برای مالک فایل، ‎"r-x"‎ (خواندن و اجرا، اما نوشتن خیر) برای اعضای گروه فایل، و ‎"r-x"‎ (خواند و اجرا) برای سایر کاربران می‌باشیم. بعضی از خط تیره‌ها با حروف جایگزین شده‌اند. سایر خط تیره‌ها به طور غیر فعال، برای نشان دادن آنکه مجوزهای متناظرشان(مجوز نوشتن گروه و سایرین) برای این فایل فعال نگردیده‌اند، باقی می‌مانند.

در واقع، رشته مجوز که ls در خروجی می‌نویسد، همیشه حداقل برای وضعیت‌های معمولی دارای همان نشانه‌ها در همان موقعیت‌ها می‌باشد. (موارد استثنا را بعداً خواهیم دید.) .در حقیقت ضرورتی برای قرار دادن یک r به جای یک w وجود ندارد. به سادگی به واسطه محل حرف می‌توانستیم بگوییم که کدام مجوز فعال است. استفاده از یک ‎"r"‎ به جای یک ‎"x"‎ در ستون اول واقعاً سهولتی برای آسانتر خواندن فراهم می‌کند.

بیایید به جای نوشتن یک حرف، یک ‎"1"‎ بنویسیم. اجازه بدهید به جای نوشتن خط تیره یک ‎"0"‎ بگذاریم. اکنون رشته مجوز ‎"rwxr-xr-x"‎ اینطور خواهد شد:

rwxr-xr-x
111101101

این یک نمایش باینری(مبنای 2) یک عدد است، و در واقع این عدد است که برای نگهداری مجوزهای این فایل در سیستم فایل ذخیره می‌شود. ls این عدد را از فایل‌سیستم به دست می‌آورد(با استفاده از فراخوان سیستمی ‎stat(2)‎‎) و سپس آنرا به رشته‌ای که شما در نمایشگر می‌بینید تبدیل می‌کند.

متأسفانه برای ما انسانها، کار کردن با اعداد باینری خیلی خوش‌آیند نیست. آنها واقعاً طویل هستند و موقعی که تعداد زیادی از آنها همراه یکدیگر در یکجا قرار دارند، شمارش آنها به آسانی اشتباه می‌شود، به طوری که ممکن است به طور اتفاقی اشتباه بشوند. می‌توانستید از کاما در میان آنها استفاده کنید،مشابه وقتی که عدد ‎"1,000,000"‎ را برای نمایش یک میلیون می‌نویسیم(مطابق عرفUSA)، اما حقیقتاً روش مناسب‌تری برای مدیریت اعداد باینری موجود است. ما آنها را به اکتال(مبنای 8) یا هگزادسیمال(مبنای 16) تبدیل می‌کنیم.

موقعی که یک عدد دودویی را به هگزادسیمال تبدیل می‌کنید، در حقیقت کاری که انجام می‌دهید، گروه‌بندی چهار بیت(bit) در یک مرحله و تعویض هر گروه چهار رقمی دودویی با یک رقم «هگزا» است، که یک عدد از ‎0-9‎ یا یک حرف از ‎A-F‎ می‌باشد. این کار برای برخی مقاصد بسیار خوب است، اما برای این وظیفه،نتیجه شده که اکتال بیشتر مناسب می‌باشد.

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

rwxr-xr-x

111101101
\_/\_/\_/
 |  |  |
 |  |  |
 |  +--+------است ‎5‎ یا ‎4 + 0 + 1‎ (دو دویی) ‎101‎ ‎
 |
 |
 |
 +------------است ‎7‎ یا ‎4 + 2 + 1‎ (دو دویی) ‎111‎

بنابراین ‎"rwxr-xr-x"‎ معادل عدد اکتال ‎"755"‎ می‌باشد. علاوه براین، هر رقم در این عدد اکتال دقیقاً با یک گروه از مجوزها همخوانی دارد -- مالک، گروه، و دیگران. اگر ما فرمان ‎chmod 740 filename‎ را دیده بودیم، اکنون بلادرنگ، حتی بدون نگاه کردن به دو رقم دیگر می‌دانستیم که مجوزهای مالک فایل ‎"rwx" (7)‎ می‌شود.

یک لحظه تأمل نیز به شما اجازه می‌دهد تعیین کنید سایر بیت‌های مجوز به چه موردی تنظیم خواهند شد. یک ‎"r"‎ همیشه با یک 4 مطابقت دارد، ‎ "w"‎ همیشه 2 است، و "x" همیشه 1 است. شما به سادگی می‌توانید آنها را برای بدست آوردن عدد اکتال جمع کنید، یا می‌توانید عدد اکتال را برای به دست آوردن حروف، در ذهن خود به نماینده دو دویی آن تجزیه کنید. پس از اینکه چند بار این کار را انجام بدهید، تقریباً خودکار خواهد شد.

این هم جدولی برای کمک به شما جهت استخراج اعداد:

rwx  7  (4 + 2 + 1)
rw-  6  (4 + 2)
r-x  5  (4 + 1)
r--  4
-wx  3  (2 + 1)
-w-  2
--x  1
---  0

با استفاده از این جدول، می‌توانیم ببینیم که ‎chmod 740‎ به معنی آن است که مجوزهای حاصل ‎rwx‎، سپس ،r--‎، بعد ‎---‎، یا ‎rwxr-----‎ خواهند شد، یعنی مجوزهای کامل برای مالک، فقط خواندن برای گروه، و برای سایر کاربران هیچ.

umask

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

یک umask نوعی می‌تواند 022 باشد، که ما آن را به صورت ‎----w--w-‎ معنی می‌کنیم، یا «نوشتن گروه و نوشتن سایرین». اگر ما umask خود را به 022 تنظیم کنیم، یعنی به کرنل می‌گوییم که هر وقت ما فایل جدیدی ایجاد می‌کنیم، ما نمی‌خواهیم به طور پیش‌فرض برای گروه یا همگان قابل نوشتن باشد. در اینجا مثالی با استفاده از فرمان خارجی ‎touch(1)‎ آورده‌ایم. به خاطر داشته باشید که touch از umask پوسته، هر نوبت که ایجاد می‌شود ارث می‌برد.

griffon:~$ umask 022; touch testfile
griffon:~$ ls -l testfile
-rw-r--r--  1 greg greg 0 2005-03-11 09:54 testfile

وقتی touch فایلی را ایجاد می‌کند(چون در مثال ما testfile هنوز وجود نداشت)، به کرنل می‌گوید با کاربرد مجوز اکتال 666 (یا ‎rw-rw-rw-‎) فایل را ‎open(2)‎ نماید. اما کرنل بیت‌هایی را که در umask معین شده‌اند، حذف می‌کند، بنابراین نتیجه آنست که بالا دیدیم. این هم یک نگاه نزدیک‌تر به آن:

griffon:~$ rm testfile
griffon:~$ strace -eopen touch testfile
open("/etc/ld.so.preload", O_RDONLY)    = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
open("/lib/libc.so.6", O_RDONLY)        = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
open("testfile", O_WRONLY|O_NONBLOCK|O_CREAT|O_NOCTTY|O_LARGEFILE, 0666) = 3

چند سطر اول را چشم‌پوشی کنید، زیرا فقط مربوط به کتابخانه‌ها هستند. ما به سطر آخر توجه می‌کنیم، که در آن ‎"testfile"‎ با مجوز 0666 باز می‌شود. (اعداد اکتال در زبان C برای متمایز نمودن آنها از اعداد معمولی مبنای10 با یک 0 مقدم نوشته می‌شوند). فرمان touch مجوز 0666 را درخواست می‌کند، اما کرنل 0022 را که ما در umask تعیین کرده‌ایم از آن حذف نموده، و نتیجه به جای 0666 برابر 0644 ‎(rw-r--r--)‎ گردیده است.

(به اشتباه فکر نکنید که کرنل این کار را با تفریق 022 از 666 انجام می‌دهد. عملیات واقعی با منطق بیتی انجام می‌گردد. بهتر است اینطور در نظر بگیرید که تمام بیت‌های umask، اگر در عدد اصلی وجود داشته باشند، «قلم خورده» می‌شوند.)

اکنون بیایید فرض کنیم کاربر بدگمانی داریم که می‌خواهد هرگز هیچ شخص دیگری فایلهایش را نخواند. او umask خود را به 077 تنظیم کرده است. در آن حالت این چیزی است که ما می‌بینیم:

griffon:~$ rm testfile
griffon:~$ umask 077; strace -eopen touch testfile 2>&1 | tail -1; ls -l testfile
open("testfile", O_WRONLY|O_NONBLOCK|O_CREAT|O_NOCTTY|O_LARGEFILE, 0666) = 3
-rw-------  1 greg greg 0 2005-03-11 10:01 testfile

مانند قبل، touch نگران مقدار umask نیست. دقیقاً ‎open(2)‎ را با مجوزهای مطلوب 0666 فرا می‌خواند، و کرنل umask را اِعمال می‌کند. در این حالت umask ما برابر 0077 یا ‎---rwxrwx‎ است، بنابراین آنها مجوزهایی هستند که ما خط می‌زنیم. تمام آنچه باقی می‌ماند ‎rw-‎ برای مالک فایل است، مجوزهای گروه و سایرین همگی حذف شده‌اند، و ما ‎rw------- (0600)‎ را داریم.

همین روشهای اجرایی برای دایرکتوریها به کار می‌رود. تنها تفاوت آن است که دایرکتوریها به طور پیش‌فرض با مجوزهای اجرا(0777 به جای 0666) ایجاد می‌شوند. بیایید نگاهی به این مورد داشته باشیم:

griffon:~$ umask 022; strace -emkdir mkdir testdir; ls -ld testdir
mkdir("testdir", 0777)                  = 0
drwxr-xr-x  2 greg greg 512 2005-03-11 10:05 testdir/

در این مثال چند مورد جدید وجود دارد، بنابراین اجازه دهید به هر یک از آنها بپردازیم. اول آنست که ما از فرمان ‎mkdir(1)‎ استفاده کردیم که سپس فراخوان سیستم ‎mkdir(2)‎ را برای کرنل به کار می‌برد. چنانکه گفتیم ‎strace(1)‎ برای نشان دادن آن فراخوان سیستم به ما می‌باشد. بعد، می‌بینیم که mkdir (فرمان) به کرنل گفت این دایرکتوری را بامجوز 0777 ( که ‎rwxrwxrwx‎ خواهد شد)، mkdir(فراخوان سیستم) نماید. اما کرنل بیت‌های umask را حدف نمود، به طوری که به ‎rwxr-xr-x (0755)‎ منجر گردید. سرانجام، ما از گزینه ‎-d‎ برای آن استفاده کردیم که به ls بگوییم خود دایرکتوری را به ما نشان بدهد نه محتویات آن را، آنطور که وقتی به طور معمول به ls می‌گویید یک دایرکتوری را لیست کند، انجام می‌دهد. ستون اول خروجی به جای خط تیره یک d است، به علت آنکه این یک دایرکتوری است و نه یک فایل معمولی. کاراکتر / در انتها به خاطر آنست که ‎"greg"‎ یک مستعار یا یک تابع دارد، در حال حاضر می‌توانید از آن صزفنظر نمایید.

اینجا همان مثال است با یک umask متفاوت:

griffon:~$ rmdir testdir
griffon:~$ umask 027; mkdir testdir; ls -ld testdir
drwxr-x---  2 greg greg 512 2005-03-11 10:09 testdir/

این اولین بار است که دیده‌ایم مجوزهای گروه با مجوزهای سایر کاربران تفاوت دارد. یک umask برابر 027 به معنی آنست که «ما می‌خواهیم گروه ما مجوز نوشتن نداشته باشد، اما بتواند بخواند و اجرا کند، هر کاربر دیگر هیچ مجوزی نداشته باشد». و آنچه واقعاً در انتها می‌بینیم این است: ‎rwxr-x---‎، یا 0750.

مجوزهای دایرکتوری

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

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

pegasus:~$ uname -a
OpenBSD pegasus 3.6 PEGASUS#1 i386
pegasus:~$ mkdir testdir; echo s3kr3tdata > testdir/secret; chmod 400 testdir
pegasus:~$ ls -ld testdir   
dr--------  2 greg  greg  512 Mar 11 10:19 testdir/
pegasus:~$ ls testdir
pegasus:~$ echo testdir/*
testdir/secret
pegasus:~$ ls -l testdir/*
ls: testdir/secret: Permission denied
pegasus:~$ cat testdir/secret
cat: testdir/secret: Permission denied

این است چگونگی رفتار یک یونیکس سنتی با خواندن، اما نه اجرای دایرکتوریها. پوسته می‌تواند فایل داخل دایرکتوری را «ببیند»، زیرا قادر است نام فایل را با خواندن دایرکتوری به طریق واقعی، به دست آورد. (یک دایرکتوری دقیقاً لیستی از نام فایلها و شماره‌های زیرنویس 1 inode آنها می‌باشد). اما نمی‌تواند کاری روی فایلهای آن دایرکتوری انجام بدهد -- نمی‌تواند آنها را باز کند، و نمی‌تواند اطلاعات آنها را نمایش بدهد. بنابراین ‎ls -l‎ شکست می‌خورد(نمی‌تواند اطلاعات آنرا نمایش دهد)، و ‎cat‎ موفق نمی‌شود(نمی‌تواند باز کند).

این هم همان تنظیم، روی یک سیستم دبیان است. من باید برای این مثال به دایرکتوری ‎/tmp‎ تغییر مکان بدهم، زیرا نتایجی که در دایرکتوری خانگی خود به دست آوردم غیر عادی بود(به علت اینکه دایرکتوری خانگی من به NFS متصل --mount-- می‌شود، نه یک فایل سیستم محلی).

griffon:/tmp$ uname -a
Linux griffon 2.4.28 #1 Thu Jan 6 08:29:18 EST 2005 i686 GNU/Linux
griffon:/tmp$ mkdir testdir; echo s3kr3tdata > testdir/secret; chmod 400 testdir
griffon:/tmp$ ls testdir
ls: testdir/secret: Permission denied
griffon:/tmp$ echo testdir/*
testdir/secret
griffon:/tmp$ ls -l testdir
ls: testdir/secret: Permission denied
total 0

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

مجوز نوشتن یک دایرکتوری به شما اجازه می‌دهد در آن دایرکتوری فایلها را ایجاد کنید، تغییر نام داده یا حذف نمایید(با یک استثنا، بعداً نشان داده می‌شود).

به من اجازه بدهید برای کسانی که خیلی به سرعت می‌خوانند یک بار بیشتر بگویم. مجوز نوشتن یک دایرکتوری به شما اجازه می‌دهد فایلها را از دایرکتوری حذف کنید. با یک استثنا که من بعداً نشان خواهم داد. من چیزی در مورد مالکیت یا حتی مجوز خود فایل نگفتم. آنها مطرح نیستند.

این هم یک مثال:

griffon:~$ mkdir testdir; sudo touch testdir/foo; ls -la testdir
total 20
drwxr-xr-x    2 greg greg   512 2005-03-11 10:29 ./
drwxr-xr-x  150 greg greg 19456 2005-03-11 10:29 ../
-rw-r--r--    1 root greg     0 2005-03-11 10:29 foo
griffon:~$ rm testdir/foo
rm: remove write-protected regular empty file `testdir/foo'? y
griffon:~$ ls -la testdir
total 20
drwxr-xr-x    2 greg greg   512 2005-03-11 10:29 ./
drwxr-xr-x  150 greg greg 19456 2005-03-11 10:29 ../

آن فایل در مالکیت Root است، اما کاربر greg قادر به حذف آن بود. چرا؟ به دلیل آنکه greg در آن دایرکتوری که بود، دارای مجوز نوشتن در آن بود. این حقیقت که فایل در مالکیت root بود، فقط باعث آن گردید که ‎rm(1)‎ برای تایید از ما سؤال کند، اما ما را از انجام آن باز نمی‌دارد. اگر می‌خواستیم از مرحله تأیید عبور کنیم، می‌توانستیم گزینه ‎-f (force)‎ را به فرمان rm عبور بدهیم، و فایل بدون سر و صدا حذف می‌گردید.

آخرین اما نه کمترین، مجوز اجرای یک دایرکتوری به شما اجازه می‌دهد به آن دایرکتوری ‎chdir(2)‎ (تعویض دایرکتوری) نمایید، و همچنین اجازه می‌دهد فایلهای آنجا را باز کنیم یا اطلاعات آنها را نمایش دهیم. باز کردن یک فایل به مجوزهای مقتضی خود فایل نیز احتیاج دارد. در عمل، تقریبا هرگز شما دایرکتوری که مجوز خواندن برای برخی کاربران را داشته باشد، اما بیت متناسب اجرا را نداشته باشد، نخواهید دید. برای مقاصد عملی، همواره باید اطمینان حاصل کنید دایرکتوری که دارای "r" هست، دارای "x" نیز باشد -- در غیر اینصورت، به طوری که قبلاً دیدیم، "r" تنها خیلی خوب برای ما کار نمی‌کند.

آیا هرگز جایی هست که شما بخواهید یک دایرکتوری "x" داشته باشد اما "r" نداشته باشد؟ بلی. این مورد موقعی سودمند واقع می‌شود که شما می‌خواهید به اشخاص اجازه بدهید در صورتیکه نام فایل‌هایی در دایرکتوری را می‌دانند به آنها برسند، اما قادر به پی بردن به نام فایلها نباشند. همچنین، اگر شما یک محل ناشناس ارسال فایل(upload) را تنظیم نموده‌اید، و نمی‌خواهید اشخاص قادر به دیدن فایلهایی باشند که دیگران به آنجا ارسال نموده‌اند، تا فرصت از فیلتر عبور دادن فایلهای نامطلوب را داشته باشید، می‌تواند سودمند باشد.

اما رایج‌ترین موردی که شما یک "x" روی دایرکتوری بدون داشتن "r" می‌بینید، وقتی است که کاربری دارای یک پایگاه اینترنتی تنظیم شده روی دایرکتوری ‎~/public_html‎ خود می‌باشد، اما نمی‌خواهد دایرکتوری خانگی‌اش به طور کامل برای جهان قابل رؤیت باشد. برای آپاچی(Apache) جهت به دست آوردن فایلها در ‎public_html‎، دایرکتوری خانگی‌اش باید "x" (قابل اجرا) برای تمام کاربران باشد، و همچنان برای خود ‎public_html‎ . بنابراین شاید او تنظیمی به این صورت داشته باشد:

drwxr-x--x  150 jane jane 19456 2005-03-11 10:29 /home/jane
drwxr-x--x   14 jane jane  5632 2005-02-11 08:48 /home/jane/public_html
-rw-r--r--    1 jane jane  1226 2004-11-04 10:05 /home/jane/public_html/index.html

اکنون سایر کاربران سیستم( خارج از گروه "jane" ) نمی‌توانند ببینند jane چه فایلهایی در دایرکتوری خانگی خود دارد، و آنها نمی‌توانند آنچه او در دایرکتوری public_html خود دارد را ببینند، اما آپاچی می‌تواند فایل ‎index.html‎ را باز کند. (آپاچی به مجوز "x" برای تمام دایرکتوری‌های منجر به فایل ‎index.html‎، نیاز دارد و به مجوز "r" برای خود فایل به منظور باز کردن و خواندن آن احتیاج دارد.)

این به طور واقعی فایلهای jane را از چشمان کنجکاو، اگر که آنها اتفاقاً نام فایل را بدانند، محافظت نمی‌کند. به عنوان مثال، شاید john بخواهد ببیند jane چه مستعارهایی استفاده می‌کند، بنابراین شاید از ‎cat ~jane/.bashrc‎ استفاده کند و امیدوار باشد که او یک فایل ‎.bashrc‎ داشته باشد که او می‌تواند از آن متوجه شود. اگر jane یک فایل ‎.bashrc‎ دارد، و آن برای همگان قابل خواندن است، آنوقت john ، حتی اگر نتواند یک فرمان ‎ls -l‎ روی آن اجرا کند، قادر به خواندن آن خواهد بود. اگر jane می‌خواهد در حالیکه بازهم دایرکتوری public_html را برای استفاده آپاچی حفظ می‌کند، محتویات فایلهایش به خوبی نامها مخفی باشد، آنوقت او مجوزهای دیگران برای خود فایلها را باید حذف کند. این به معنای آن است که احتمالاً می‌خواهد از umask برابر 027 استفاده کند. تنها موضوع باقی‌مانده برای jane آن است که هر وقت فایل جدیدی به دایرکتوری public_html اضافه می‌کند، باید آن را برای آپاچی قابل خواندن همگانی کند. متأسفانه راهی برای jane وجود ندارد که یک umask برابر 022 برای ‎~/public_html‎ و یک umask معادل 027 برای تمام دایرکتوری‌های دیگر تنظیم کند. umaskها «یک بر پردازش» هستند نه «یک بر دایرکتوری».

بیت‌های Sticky و setuid و setgid

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

اولین مورد از این بیت‌های ویژه ‎"sticky bit"‎ نامیده می‌شود، که یک نام تاریخی است و چیزی در مورد آنچه واقعاً این بیت انجام می‌دهد به شما نمی‌گوید. تقریباً تنها زمانی که آن را روی یک سیستم دبیان خواهید دید موقعی است که مجوزهای دایرکتوری ‎/tmp‎ را مشاهده می‌کنید:

griffon:~$ ls -ld /tmp
drwxrwxrwt  14 root root 4096 2005-03-11 10:06 /tmp/

حرف "t" در انتهای رشته مجوز(به جای "x" که انتظار داشتیم ببینیم) به معنای آن است که بیت sticky این دایرکتوری روشن شده. وقتی یک دایرکتوری بیت sticky روشن شده دارد، هیچکس نمی‌تواند فایلهای شخص دیگری را از آن دایرکتوری حذف کند یا تغییر نام بدهد، ولو اینکه مجوز نوشتن در آن دایرکتوری را داشته باشد. به خاطر می‌اورید که greg فایلی در مالکیت root را حذف نمود؟ او همان کار را نمی‌تواند در دایرکتوری ‎/tmp‎ انجام بدهد:

griffon:/tmp$ sudo touch foo; ls -ld . foo
drwxrwxrwt  14 root root 4096 2005-03-11 10:46 ./
-rw-r--r--   1 root root    0 2005-03-11 10:46 foo
griffon:/tmp$ rm -f foo
rm: cannot remove `foo': Operation not permitted

با وجود داشتن مجوز نوشتن در ‎/tmp‎ (و بنابراین توانایی ایجاد فایلها در آنجا)، greg نمی‌تواند فایل root را حذف کند، این به علت روشن بودن بیت sticky در ‎/tmp‎ است. این مطلب اهمیت دارد، زیرا ما نمی‌خواهیم کاربران قادر به حذف فایلهای موقتی سایر اشخاص باشند و برنامه‌های آنها را که به استفاده از آن فایلها نیاز دارند، سر در گم نمایند.

منشاء مفهوم "sticky bit" به روزهای اولیه یونیکس باز می‌گردد، زمانی که مطالبه سطح بالای الگوریتم‌های صفحه‌بندی برای مدیریت حافظه نداشتیم. یک پردازش یا می‌توانست در حافظه باشد، یا در حافظه نباشد. اگر کرنل به حافظه اضافی برای پردازش جدیدی نیاز داشت، به جای صفحات انتخابی از پردازش ، می‌بایست پردازش کامل را برای ایجاد فضا، با دیسک مبادله کند‎(swap)‎. همچنین موقعی که اجرای برنامه‌هامتوقف می‌شد، تصویر کامل برنامه در حافظه از بین می‌رفت( نه فقط قطعه داده‌های آن). بنابراین در آن سیستم‌های قدیمی، بیت "sticky" روی یک فایل برنامه(نه دایرکتوری) به معنای آن بود که کد برنامه پس از اتمام اجرای آن می‌باید در حافظه رها می‌شد، زیرا محتمل بود به زودی دوباره درخواست بشود. مثال کلاسیک یک برنامه sticky فایل ‎/bin/ls‎ بود، که در تمام اوقات همه به کار می‌بردند. نگهداری آن در حافظه کارایی سیستم را روی هم رفته بالا برده بود. اگرچه نگهداری مورد تنومندی همچون مترجم C در حافظه، به کارایی در آن سیستم‌های قدیمی‌تر آسیب می‌رساند، زیرا آنها حافظه زیادی برای چشم‌پوشی نداشتند. به هر حال این هیچ در مورد سیستم دبیان صدق نمی‌کند. این پاراگراف تنها به واسطه اشاره تاریخی در اینجا آورده شد.

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

بهترین مثال یک برنامه setuid فرمان ‎passwd(1)‎ است که به کاربران اجازه می‌دهد کلمه عبورشان را تغییر بدهند. این برنامه باید قادر باشد محتویات فایل ‎/etc/passwd‎ را ویرایش کند، اما به طور حتم ما نمی‌خواهیم کاربران عادی این توانایی را داشته باشند! از اینرو برنامه passwd به طور بسیار با دقتی نوشته شده است، به طوری که فقط انجام حداقل تغییر ضروری را به کاربر جهت تغییر کلمه عبور خودش اجازه می‌دهد. پس بیت setuid فعال شده است، به طوری که قدرت انجام آن تغییر را دارد.

griffon:~$ ls -l /usr/bin/passwd
-rwsr-xr-x  1 root root 26616 2004-07-27 10:39 /usr/bin/passwd*

حرف "s" در جایی که ما انتظار دیدن یک "x" برای مجوز مالک داشتیم به معنای آن است که این برنامه دارای هر دو بیت تنظیم شده اجرا و setuid می‌باشد. موقعی که greg کلمه "passwd" را تایپ می‌کند، برنامه passwd به جای greg به عنوان root اجرا می‌شود.

به همچنین، برنامه‌های setgid به جای شماره شناسایی گروه شخصی که برنامه را راه‌اندازی می‌کند، با شماره شناسایی گروه مالک گروهشان اجرا می‌شوند. یک مثال خوب ‎xterm(1)‎ است:

-rwxr-sr-x  1 root utmp 263736 2004-12-15 14:19 /usr/bin/X11/xterm*

xterm به عنوان عضوی از گروه "utmp" اجرا می‌شود، به طوری که می‌تواند یک مدخل در فایل ‎utmp(5)‎ بنویسد:

-rw-rw-r--  1 root utmp 11904 2005-03-11 08:09 /var/run/utmp

این فایل توسط برنامه ‎who(1)‎ و سایر برنامه‌ها برای نگهداری یک رکورد از شخصی که به سیستم متصل گردیده، مورد استفاده قرار می‌گیرد. وقتی یک xterm با نشانه‌های معین اجرا می‌شود، یک مدخل در داخل این فایل می‌نویسد، بنابراین، افرادی که از طریق شبکه به وسیله اجرای یک xterm و تعدادی برنامه داخل آن به سیستم متصل می‌شوند، را در خروجی برنامه "who" نمایش خواهد داد. (این یک توضیح بسیار ضعیف و ساده‌سازی شده از چگونگی عملکرد utmp است، اما این صفحه تا اینجا هم بیش از اندازه حجیم شده است.)

عاقبت، یک نکته نهایی، و به پایان خواهیم برد. بیت setuid روی دایرکتوری مصداق ندارد(در دبیان)، اما بیت setgid دارد. به معنای آن است که فایلهای ایجاد شده در آن دایرکتوری به جای GID شخصی که آنها را ایجاد می‌کند از مالک گروه دایرکتوری ارث می‌برند.موقعی که این بیت با یک umask که امتیاز نوشتن گروه را مجاز می‌کند(از قبیل 002) ترکیب می‌شود، این مورد در برقراری حوزه‌ای که گروهی از کاربران می‌توانند با یکدیگر کار کنند سودمند می‌شود. برای مثال:

drwxrwsr-x  15 root src 4096 2005-01-06 08:52 /usr/src

دایرکتوری ‎/usr/src‎ توسط اعضای گروه "src" قابل نوشتن است، و همچنین دارای بیت setgid فعال شده است(نشان داده شده به صورت یک "s")، بنابراین هر فایل ایجاد شده در آن نیز به گروه "src" تعلق دارد. اگر ما دارای دو کاربر در گروه "src" باشیم (فرض کنید، john و jane)، و اگر آنها هر دو umask خود را به 002 یا 007 تنظیم کنند(حداقل در حالیکه در آن دایرکتوری کار می‌کنند)، آنوقت هرچه آنها در اینجا ایجاد کنند نیز برای گروه src قابل نوشتن خواهد بود:

drwxrwsr-x  15 root src 4096 2005-01-06 08:52 /usr/src
-rw-rw----   1 jane src  856 2004-09-06 15:26 /usr/src/foo.c
-rw-rw-r--   1 john src  952 2004-09-03 13:21 /usr/src/bar.c

در این مثال کاملاً ساختگی، jane در حالیکه در اینجا مشغول به کار است از umask برابر 007 در حال استفاده است، یا از ‎chmod(1)‎ برای انجام همان عمل استفاده نموده است. john از یک umask برابر 002 (یا chmod) استفاده می‌کند. سایر کاربران سیستم قادر خواهند بود کد john را بخوانند، اما کد jane را خیر. اما بخش مهم آن است که آنها می‌توانند هر یک از فایلهای دیگر را هم بخوانند و هم در آنها بنویسند . البته این جایگزین برای یک سیستم کنترل نگارش با انضباط نیست، بلکه رایج‌ترین مورد استفاده از بیت setgid برای یک دایرکتوری را تشریح می‌کند.

در برخی سیستم‌ها(از جمله دبیان با coreutils نگارش ‎6.0‎ یا بالاتر)، فرمانchmod موقعی که در وضعیت اکتال استفاده می‌شود، بیت‌های setuid و setgid را از دایرکتوری پاک نمی‌کند. در سایر سیستم‌ها ‎chmod 755‎ همیشه مجوزهای دایرکتوری را به صورت ‎drwxr-xr-x‎ تنظیم می‌کند، و نه مورد دیگری. بنابراین اگر در وضعیتی قرار گرفتید که آنجا فرمان ‎chmod 755 somedir‎ در پاک کردن بیت setuid یا setgid ناموفق شد، شما باید از symbolic mode( مترجم: استفاده از حروف مربوطه rwx ) برای بیان صریح مقاصد خود استفاده نمایید. برای توضیحات بیشتر صفحات man سیستم خود را ببینید.


CategoryUnix

مجوزها (آخرین ویرایش ‎2011-06-27 17:47:07‎ توسط GreyCat)


  1. مترجم: inode ساختار داده‌ای نگهدارنده اطلاعات فایلها در سیستم فایل یونیکس است. برای هر فایل یک inode وجود دارد و فایل منحصراً توسط سیستم فایلی که در آن مستقر است و شماره inode فایل، شناسایی می‌گردد. هر فایل دارای چند جزء تشکیل‌دهنده می‌باشد، نام فایل، محتویات آن، و اطلاعات مدیریتی. اطلاعات مدیریتی در inode ذخیره می‌گردد و شامل این موارد است: دستگاهی که فایل روی آن مستقر است، اطلاعات قفل شدگی، وضعیت و نوع فایل، تعداد پیوند به فایل، شماره شناسایی‌های کاربر مالک فایل و گروه آن، تعداد بایتهای فایل، زمان آخرین ویرایش(نوشتن) فایل، آخرین زمان دستیابی(خواندن یا اجرا)، زمان آخرین تغییر خود inode (مانند تغییر مجوز فایل) و آدرس بلوکهای فایل روی دیسک. شماره inode فایل را می‌توان با استفاده از فرمان ls همراه گزینه ‎-i‎ به دست آورد. البته شماره‌ای که در این حالت نمایش داده می‌شود، آدرس اولین بلوک فایل روی دیسک است، که می‌توان از آن برای دریافتن آنکه آیا دو فایل با نامهای متفاوت دقیقاً یکسان می‌باشند(پیوندها) استفاده نمود. (بازگشت)


نمایش متن رنگی

نمایش متن رنگی

چطور می‌توانم متن را با رنگهای مختلف چاپ کنم؟

در برنامه خود از رشته‌های escape رنگ ANSI استفاده نکنید! فرمان tput محاوره با بانک اطلاعاتی ترمینال به روشی معقول، را برای شما میسر می‌سازد:

  # Bourne
  tput setaf 1; echo this is red
  tput setaf 2; echo this is green
  tput bold; echo "boldface (and still green)"
  tput sgr0; echo back to normal

کاربران Cygwin: شما برای به دست آوردن tput نیاز به نصب بسته ncurses دارید( Where did "tput" go in 1.7? را ببینید).

tput بانک اطلاعاتی terminfo را می‌خواند که شامل تمام کُدهای escape لازم برای محاوره با ترمینال شما می‌باشد. این کدها در متغیر ‎$TERM‎ تعیین شده‌اند. برای اطلاعات تفصیلی صفحه‎ man terminfo(5)‎ را بخوانید.

دستور ‎tput sgr0‎ رنگها را دوباره به مقادیر پیش فرض تنظیم می‌کند. این دستور همچنین حالت حروف ضخیم ‎(tput bold)‎‏، underline، و غیره را غیر فعال می‌کند.

اگر رنگهای تفننی برای اعلان فرمان خود می‌خواهید، استفاده از مورد قابل مدیریت را در نظر بگیرید:

  # Bash
  red=$(tput setaf 1)
  green=$(tput setaf 2)
  blue=$(tput setaf 4)
  reset=$(tput sgr0)
  PS1='\[$red\]\u\[$reset\]@\[$green\]\h\[$reset\]:\[$blue\]\w\[$reset\]\$ '

توجه نمایید که ما از رشته‌های escape رنگ ANSI استفاده نکردیم. به جای آن ذخیره خروجی فرمان tput در متغیرها را به کار بردیم، که بعداً هنگامی که ‎ $PS1‎ بسط داده می‌شود، به کار می‌روند. ذخیره کمیت‌ها به معنای آنست که در هر نوبت نمایش اعلان، چندین انشعاب پردازش tput نداریم، tput فقط چهار بار در حین شروع اولیه پوسته فراخوانی می‌شود. علائم‎ \[‎ و ‎\]‎ اجازه می‌دهند bash بفهمد کدام قسمت‌های اعلان موجب حرکت نشانگر نشوند، بدون آنها سطرها به طور نادرست شکسته خواهند شد.

همچنین برای یک مرور اجمالی http://wiki.bash-hackers.org/scripting/terminalcodes ببینید.

در ادامه دامنه وسیع‌تری از رشته متغیرهای ترمینال آمده است. هر کدام را که می‌خواهید برگزینید:

# .متغیرها برای درخواستهای ترمینال
[[ -t 2 ]] && { 
    alt=$(      tput smcup  || tput ti      ) # Start alt display
    ealt=$(     tput rmcup  || tput te      ) # End   alt display
    hide=$(     tput civis  || tput vi      ) # Hide cursor
    show=$(     tput cnorm  || tput ve      ) # Show cursor
    save=$(     tput sc                     ) # Save cursor
    load=$(     tput rc                     ) # Load cursor
    bold=$(     tput bold   || tput md      ) # Start bold
    stout=$(    tput smso   || tput so      ) # Start stand-out
    estout=$(   tput rmso   || tput se      ) # End stand-out
    under=$(    tput smul   || tput us      ) # Start underline
    eunder=$(   tput rmul   || tput ue      ) # End   underline
    reset=$(    tput sgr0   || tput me      ) # Reset cursor
    blink=$(    tput blink  || tput mb      ) # Start blinking
    italic=$(   tput sitm   || tput ZH      ) # Start italic
    eitalic=$(  tput ritm   || tput ZR      ) # End   italic
[[ $TERM != *-m ]] && { 
    red=$(      tput setaf 1|| tput AF 1    )
    green=$(    tput setaf 2|| tput AF 2    )
    yellow=$(   tput setaf 3|| tput AF 3    )
    blue=$(     tput setaf 4|| tput AF 4    )
    magenta=$(  tput setaf 5|| tput AF 5    )
    cyan=$(     tput setaf 6|| tput AF 6    )
}
    white=$(    tput setaf 7|| tput AF 7    )
    default=$(  tput op                     )

    eed=$(      tput ed     || tput cd      )   # Erase to end of display
    eel=$(      tput el     || tput ce      )   # Erase to end of line
    ebl=$(      tput el1    || tput cb      )   # Erase to beginning of line
    ewl=$eel$ebl                                # Erase whole line
    draw=$(     tput -S <<< '   enacs
                                smacs
                                acsc
                                rmacs' || { \
                tput eA; tput as;
                tput ac; tput ae;         } )   # Drawing characters
    back=$'\b'
} 2>/dev/null ||:

در بالا موقعی که stderr به ترمینال متصل نباشد، متغیرهای تنظیم نشده رها می‌شوند و متغیر های رنگ تنظیم نشده برای ترمینالهای تک رنگ چشم‌پوشی می‌شوند. اجراهای جایگزین tput به کد اجازه می‌دهند روی سیستم‌هایی که در آنها tput به جای نامهای ANSI مربوطه، نام‌های قدیمی termcap را می‌پذیرد، کار را ادامه دهد. این کد همچنین از ‎2>/dev/null ||:‎ برای خاموش کردن خطاهای بالقوه و پرهیز از عدم پیشروی اسکریپت در اثر خطا، استفاده می‌کند. این مورد اجازه می‌دهد این کد در گستره‌ای از وضعیت‌ها از قبیل آن اسکریپت‌ها که ‎set -e‎ را به کار می‌برند و ترمینال‌ها یا سیستم عامل‌هایی که از رشته‌های معینی پشتیبانی می‌کنند، قابل استفاده باشد(کد از http://to.lhunath.com/bashlib اقتباس گردیده است).

مباحثه

این مطلب بحث‌انگیز خواهد بود، اما من موافقت نمی‌کنم و پیشنهاد می‌کنم از کدهای escape در ANSI به صورت hard-codedزیرنویس1 استفاده کنید به دلیل آنکه در دنیای واقعی بانک‌های اطلاعاتی مربوط به ترمینال‌ها بیشتر اوقات ناقص می‌باشند.

tput setaf‎ به طور لفظی به معنای «قرار دادن ANSI در پیش زمینه» است و نباید هیچ تفاوتی با رشته escapeهای ANSI به صورت hard-coded داشته باشد، غیر ازآنکه با بانکهای اطلاعاتی ناقص terminfo کار خواهد کرد، بنابراین رنگها در یک VT با نوع ترمینال ‎linux-16color‎ یا هر نوع ترمینال به شرطی که واقعاً ترمینالی با توانایی نمایش شانزده رنگ ANSI باشد، به طور صحیح دیده خواهند شد.

بنابراین تنظیم آن متغیرها به رشته‌های ANSI به صورت hard-coded را در نظر بگیرید.همچون:

  # Bash
  white=$'\e[0;37m'
  • شما فرض می‌کنید تمام ترمینالهای جهان که شما در هر صورت استفاده خواهید نمود همواره با یک مجموعه منفرد رشته‌های escape مطابقت می‌کنند. این یک فرض بسیار ضعیف است. شاید پیری خود را نمایش می‌دهم، اما در اولین شغل خود بعد از دانشگاه، در سال ‎1993-1994‎، با طیف متنوع گسترده‌ای از ترمینالهای فیزیکی کار کردم ‎(IBM 3151, Wyse 30, NCR or other, etc.)‎ همه در همان محل کار. تمام آنها طرح کلیدهای متفاوت، رشته‌های escape متفاوت داشتند. اگر من رشته‌های escape یک ترمینال را به طوری که شما پیشنهاد می‌کنید به صورت hard-code استفاده می‌کردم، فقط در یکی از آن ترمینالها کار می‌کرد، و سپس اگر من از اداره دیگری یا از کنسول سرویس‌دهنده لاگین می‌کردم، سردرگم می‌شدم. بنابراین، اگر برای استفاده شخصی، این کار شما را خوشحال می‌کند، من نمی‌توانم جلوی شما را بگیرم. اما اندیشه نوشتن اسکریپتی که از رشته‌های escape به طور hard-coded استفاده کند و سپس توزیع آن برای دیگران باید به فوریت دور انداخته شود. - GreyCat

    • من گفتم این بحث‌انگیز خواهد شد، اما دیدگاه جایگزینی وجود دارد. امروزه بسیاری افراد در هر طرف از لینوکس در سرویس‌دهنده‌های خود یا میزکارهایشان با پروفایلهای خود، استفاده می‌کنند. بانک اطلاعاتی ترمینال برای لینوکس ۱۶ رنگ نابسامان است. با انجام این کار به آن روش «درست»(مترجم: توجه دارید که نویسنده کلمه درست را با کنایه استفاده نموده است)، آنها متوجه خواهند شد که رنگهایشان در ترمینال مجازی یکی از ttyهای کنسول به طور صحیح کار نمی‌کند. با اجرای آن روش «نادرست»، اگر از xterm واقعی یامشتق نزدیک به آن استفاده کنند، فقط رنگ قرمز روشن پررنگ می‌شود. اگر بانک اطلاعاتی ترمینال، در مورد رایجی مانند لینوکس ۱۶ رنگ نمی‌تواند صحیح باشد، پیشنهاد تکیه‌کردن به آن مشکل است. اشخاص باید آگاه باشند که آن روش به طور صحیح کار نمی‌کند، خودتان آن ۱۶ رنگ اول را در یک ترمینال مجازی لینوکس با linux-16color امتحان کنید. من می‌دانم که ANSI فقط نامها را تعیین نموده نه رنگمایه‌ها را، اما ‎به وضوح setaf 7‎ قرار نیست به دیدن متن سیاه منجر گردد، چون white نامیده شده است. من شرط می‌بندم که افراد بیشتری برای سرویس‌دهنده‌های خود از لینوکس استفاده می‌کنند تا دیگر سیستم‌های یونیکسی، و اگر از دیگر سیستم‌های مبتنی بر یونیکس یا یونیکس حقیقی استفاده می‌کنند، احتمالاً از ریزه‌کاری‌ها آگاه می‌باشند . یک تازه‌کار در لینوکس، بعد از پیروی از «روش درست» و دریافتن آنکه رنگهایش در ترمینال مجازی به طور صحیح کار نمی‌کنند، بسیار شگفت‌زده می‌شود. البته کار درست اصلاح فایل terminfo است، اما آن کاری است که در توانایی من نیست، هرچند که من به طور خاص باگ مربوط به linux-16color راگزارش کرده‌ام، چه تعداد باگ دیگر در آن وجود دارد؟ تنها کار کاملاً صحیح، hard-code نمودن رشته‌ها برای تمام ترمینالهایی است که خودتان با آنها مواجه خواهید شد، که همان کاری است که قرار است terminfo انجام بدهد تا شما مجبور به انجام آن نشوید. به هرحال حداقل در این حالت(و حالت بسیار رایج) مشکل‌دار است، بنابراین اعتماد به آن برای انجام صحیح این کار نیز مورد تردید است. من در اینجا اضافه می‌کنم که احترام بسیاری برای Greycat قائل هستم، و او یک کارشناس خبره در بسیاری از حوزه‌های IT می‌باشد، من کاملاً قبول دارم که از چنان عمق دانشی مانند او برخوردار نیستم، اما آیا هرگز شما مشغول کار روی یک ‎Wyse 30‎ خواهید بود؟ برای اینکه کاملاً روشن شود، پیشنهاد می‌کنم که شما برای پروفایل و استفاده‌های شخصی خود، رنگهای hard-coded را در نظر بگیرید، اگر قصد نوشتن اسکریپت کاملاً قابل حملی برای استفاده دیگران در سیستم‌های بیرونی را دارید، آنوقت شما باید به ‎terminfo/termcap‎ تکیه کنید، حتی اگر دارای باگ باشند.

  • من قبلاً هرگز linux-16color نشنیده بودم. این یک مدخل terminfoنصب شده در دبیان نیست، یا حداقل به طور پیش فرض نیست. اگر فروشنده شما بانک اطلاعاتی terminfo خراب عرضه می‌کند، یک فهرست باگ گزارش کنید. ضمناً، سیستمی که مدخل مورد نیاز شما در آن خراب نیست را یافته، و آن مدخل را به سیستم خراب کپی کنید -- یا خودتان آنرا بنویسید. این کاری است که بقیه دنیا همیشه انجام می‌دهند. مدخل‌های terminfo ابتدا همین گونه به وجود آمده‌اند. کسی باید آنها را می‌نوشت.
  • console-colors.png

  • -- GreyCat


CategoryShell

پرسش و پاسخ 37 (آخرین ویرایش ‎2012-10-25 17:54:48‎ توسط Lhunath)


  1. مترجم: hard-coded به رفتاری گفته می‌شود که داده ‌ها به طور مستقیم داخل برنامه و احتمالاً در چندین محل نوشته می‌شوند به طوری که به آسانی نمی‌توانند اصلاح شوند. (1)