در 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 ...
پرسش وپاسخ 41 (آخرین ویرایش 2010-11-29 22:24:01 توسط GreyCat)
در اینجا یک نمونه هست:
# POSIX foo=$(dialog --inputbox "text goes here" 8 40 2>&1 >/dev/tty) echo "The user typed '$foo'"
در اینجا تغییرمسیر قدری مهارت آمیز است.
اول جمله foo=$(command) برقرار شده، بنابراین خروجی استاندارد فرمان توسط bash ضبط میشود.
داخل فرمان، قسمت 2>&1 باعث میشودخطای استاندارد به جایی فرستاده شود که خروجی استاندارد میرود-- به بیان دیگر اکنون stderr ضبط خواهد شد.
بخش >/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 را ببینید.
پرسش و پاسخ 40 (آخرین ویرایش 2011-01-18 18:55:21 توسط GreyCat)
صفحه فایلهای نقطهای را ملاحظه کنید
این نوشته فرض میکند شما در حال استفاده از 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 را اجرا میکند).
بیایید فرض کنیم 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 استفاده میکند. بنابراین شاید این رویکرد برای آنها کار نکند. ممکن است لازم باشد شما مستندات برنامه مدیر نمایش خود را کنکاش کنید، که پی ببرید کدام فایلها را باید برای کنترل نشستهای خود استفاده کنید.
فایلهای نقطهای (آخرین ویرایش 2011-04-21 19:06:11 توسط ppp-94-64-90-90)
مترجم: Pluggable Authentication Modules: مدولهای تصدیق اعتبار قابل تعویض کاربر برای امنیت سیستم. یک مجموعه کتابخانههای مشترک که تعین میکند کاربر چگونه اعتبار سنجی خواهد شد، به عنوان مثال، مطابق قرارداد یونیکس کاربران پس از تایپ نام کاربری خود در اعلان login با عرضه نمودن یک کلمه عبور در اعلان password خودشان را تصدیق اعتبار میکنند. در بسیاری از رویدادها از قبیل دسترسی داخلی به یک ایستگاه کاری این شکل اعتبار سنجی کافی در نظر گرفته شده است. در سایر حالتها اطلاعات بیشتری لازم میشود. اگر کاربری از یک منبع خارجی مانند اینترنت به سیستم داخلی متصل گردد، ممکن است اطلاعات بیشتر یا متناوبی لازم بشود، شاید یک کلمه عبور یکبار مصرف. PAM اینگونه توانایی و خیلی بیشتر را فراهم میکند. مهمتر از همه مدولهای pam به شما اجازه میدهند محیط خود را برای سطوح مختلف امنیتی پیکربندی کنید. (بازگشت)
مجوزها را ملاحظه کنید.
هر فایل در درون یک فایل سیستم یونیکس -- و این(فایل) هر چیزی را که میتواند در سیستم فایل یونیکس باشد، شامل میشود: فایلها، دایرکتوریها، لولههای بانام، سوکتها، دستگاههای بلوکی و کاراکتری، و پیوندهای نمادین -- دارای یک مالک، گروه، و مجموعهای از مجوزها میباشد.
در اصلیترین سطح، مجوزهای یک فایل به این طریق عمل میکنند:
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 نوعی میتواند 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 است، به علت آنکه این یک دایرکتوری است و نه یک فایل معمولی. کاراکتر
اینجا همان مثال است با یک 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 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 سیستم خود را ببینید.
مجوزها (آخرین ویرایش 2011-06-27 17:47:07 توسط GreyCat)
در برنامه خود از رشتههای 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
من گفتم این بحثانگیز خواهد شد، اما دیدگاه جایگزینی وجود دارد. امروزه بسیاری افراد در هر طرف از لینوکس در سرویسدهندههای خود یا میزکارهایشان با پروفایلهای خود، استفاده میکنند. بانک اطلاعاتی ترمینال برای لینوکس ۱۶ رنگ نابسامان است. با انجام این کار به آن روش «درست»
-- GreyCat
پرسش و پاسخ 37 (آخرین ویرایش 2012-10-25 17:54:48 توسط Lhunath)