در این مقاله شما با مدیریت سیستم عامل لینوکس و سفارشی سازی Shell لینوکس (LPIC 1) برای کار با این سیستم عامل آشنا خواهید شد. هر چند برای یادگیری بهتر این موضوع پیشنهاد می کنیم که از دوره های آموزشی لینوکس موجود در قسمت دوره های آموزشی توسینسو استفاده کنید و بصورت اصولی لینوکس یاد بگیرید.
سلام و وقت بخیر. در این دوره میخوایم اصول مدیریت سیستم های لینوکسی با استفاده از ترمینال لینوکس رو توضیح بدیم. مطالبی که ارائه خواهد شد پایه ای ترین مباحث لینوکس خواهند بود و مناسب کسانی که تازه لینوکس رو شروع کردن. سرفصل ها بیشتر جزء lpic1 خواهد بود ولی اگه لازم باشه از lpic2 یا جاهای دیگه هم میگم. کمی پیش زمینه یا مطالعه قبلی داشته باشید بهتره چون مطالب رو از صفر صفر نمیگم. امیدوارم مطالب مفید باشه. بسیار خوب. دستگاه لینوکسی خود را روشن کنید و ترمینال آنرا باز کنید.
SHELL واسط میان ما و سیستم عامل است. SHELL دستورات را از کاربر گرفته و به زبان سطح پایین قابل فهم برای سیستم عامل ترجمه میکند. SHELL ها میتوانند بصورت رابط خط دستور CLI و یا بصورت رابط گرافیکی GUI باشند. مثلا در ویندوز Command Prompt یا CMD یک SHELL است. در بسیاری از توزیع های لینوکس SHELL پیش فرض BASH است. BASH یک رابط خط دستور است. انواع دیگری از SHELL هم وجود دارد به نام های ksh و csh و bsh و ... که کمتر و در موارد خاص استفاده میشوند و ما بیشتر با همان Bash کار میکنیم.
حال ترمینال سیستم خود را باز کنید. برای اینکه بفهمید از کدام SHELL استفاده میکنید دستور زیر را وارد کنید.
[root@CentOS6 ~]# echo $0 bash [root@CentOS6 ~]#
پس روی سیستم من Bash نصب است. و اگر میخواهید بفهمید که در کجا نصب شده دستور زیر را وارد کنید.
[root@CentOS6 ~]# echo $SHELL /bin/bash [root@CentOS6 ~]#
تعریف متغیر ها در Bash بسیار ساده است. ابتدا نام متغیر و سپس مساوی و مقدار آن. (بدون space). متغیر ها حساس به حروف کوچک و بزرگ هستند، ینی متغیر color با Color فرق دارد. برای چاپ کردن محتوای یک متغیر از کلمه کلیدی echo و علامت $ قبل نام متغیر استفاده میکنیم. برای جدا کردن دستورات از ; استفاده کنید.
[root@CentOS6 ~]# color='blue' [root@CentOS6 ~]# echo $color blue [root@CentOS6 ~]# Color='red' [root@CentOS6 ~]# echo $Color red [root@CentOS6 ~]# echo $Color ; echo $color red blue [root@CentOS6 ~]# [root@CentOS6 ~]#
از دستور echo برای چاپ انواع خروجی در صفحه استفاده میشود. برای چاپ مقدار محتوای یک متغیر در جمله از ساختار زیر استفاده کنید. به تفاوت دستور ها دقت کنید.
[root@CentOS6 ~]# echo "my Tshirt is $color" my Tshirt is blue [root@CentOS6 ~]# echo 'my Tshirt is $color' my Tshirt is $color [root@CentOS6 ~]# echo my Tshirt is $color my Tshirt is blue [root@CentOS6 ~]#
برای دیدن نام کاربری که با آن وارد شدیم و مسیر home directory آن کاربر میتوانید متغیری که این مقادیر در آنها دخیره شده را چاپ کنید.
[root@CentOS6 ~]# echo $USER root [root@CentOS6 ~]# echo $HOME /root [root@CentOS6 ~]#
حال یک Shell دیگر با دستور bash باز کنید. دوباره سعی کنید که متغیر color را چاپ کنید. میبینید که همچین متغیری وجود ندارد. وقتی یک متغیر تعریف میکنیم، فقط در همان شلی که هستیم وجود دارد. برای اینکه متغیر سراسری شود، از دستور export استفاده میکنیم. هر shell یا بهتر بگم هر پروسه یک شماره شناسایی یکتا به نام pid در سیستم دارد با دستور $$ echo میتوان این شماره شناسایی یکتای شلی که در آن هستیم را ببینیم. به کد های زیر دقت کنید.
[root@CentOS6 ~]# color=red // یک متغیر تغریف کردم [root@CentOS6 ~]# echo $$ // چاپ شماره شناسایی شلی که توش هستم 11080 [root@CentOS6 ~]# bash // با این دستور یک شل جدید زیر مجموعه این شل درست کردم [root@CentOS6 ~]# echo $$ حالا شماره این شل جدید رو میخوام 11092 [root@CentOS6 ~]# echo $color // ببینم متغیر اینجا هم هست یا نه [root@CentOS6 ~]# exit // خروج از شل زیر مجموعه exit [root@CentOS6 ~]# echo $$ // مطمئن بشم تو شل قبلی هستم 11080 [root@CentOS6 ~]# export color // متعیر رو سراسری میکنم [root@CentOS6 ~]# bash // دوباره یک شل زیرمجموعه میسازم [root@CentOS6 ~]# echo $$ // میبینم که شماره شناساییش جدیده پس درست ایجاد شده 11101 [root@CentOS6 ~]# echo $color // دوباره ببینم متغیر هست یا نه red [root@CentOS6 ~]#
دستور bash اصطلاحا یک subshell میسازد. وجود این subshell وابسته به وجود پدر خود است. اگر پدر از بین رود تمام subshell ها نابود میشوند. با دستور export یک متغیر را در شل پدر در شل های فرزندش کپی کردیم. با دستور ps میتوان دید چه پروسه هایی در حال اجراست. به خوبی مشخص میشود که چند subshell در حال اجرا هستند.
[root@CentOS6 ~]# bash [root@CentOS6 ~]# bash [root@CentOS6 ~]# bash [root@CentOS6 ~]# ps PID TTY TIME CMD 11338 pts/0 00:00:00 bash 11348 pts/0 00:00:00 bash 11357 pts/0 00:00:00 bash 11368 pts/0 00:00:00 bash 11377 pts/0 00:00:00 ps [root@CentOS6 ~]#
با دستور set میتوان تمام متغیر های محلی و سراسری را نشان داد و با دستور env میتوان متغیر های export شده را دید.
در این جلسه به بررسی بعضی از تنطیمات shell میپردازیم. برای دیدن اینکه shell چه تنظیمانی دارد از دستور زیر استفاده کنید.
[root@CentOS6 ~]# set -o allexport off braceexpand on emacs on errexit off errtrace off functrace off hashall on histexpand on history on ignoreeof off interactive-comments on keyword off monitor on noclobber off noexec off noglob off nolog off notify off nounset off onecmd off physical off pipefail off posix off privileged off verbose off vi off xtrace off
برای روشن کردن یک option از set -o به همراه نام option و برای خاموش کردن آن از set +o و نام آن option استفاده میکنیم.
[root@CentOS6 ~]# set -o allexport //روشن کردن [root@CentOS6 ~]# set +o allexport //خاموش کردن
این allexport باعث میشود اگر یک با چند subshell درست کردیم، بلافاصله تمام متغیر های شل پدر در آن کپی میشود و دیگر نیاز نیست دستی، تک تک متغیر ها را export کنیم.
[root@CentOS6 ~]# set -o allexport [root@CentOS6 ~]# var1=amy [root@CentOS6 ~]# var2=taylor [root@CentOS6 ~]# bash [root@CentOS6 ~]# echo $var1; echo $var2 amy taylor [root@CentOS6 ~]#
یا مثلا اگر درون یک subshell باشیم، دکمه کنترل و d را فشار دهیم، از subshell خارج میشود. برای خاموش کردن این shortkey از یک option به نام ignoreeof استفاده میکنیم.
[root@CentOS6 ~]# set -o allexport [root@CentOS6 ~]# var1=amy [root@CentOS6 ~]# var2=taylor [root@CentOS6 ~]# bash [root@CentOS6 ~]# echo $var1; echo $var2 amy taylor [root@CentOS6 ~]# [root@CentOS6 ~]# exit [root@CentOS6 ~]# set -o ignoreeof [root@CentOS6 ~]# bash [root@CentOS6 ~]# Use "exit" to leave the shell. //اینجا کنترل و دی زده بودم که خطا داد [root@CentOS6 ~]# [root@CentOS6 ~]# exit // اینجا کلمه خروج رو نوشتم تا خارج بشه exit [root@CentOS6 ~]# [root@CentOS6 ~]#
یا یک option دیگر مثل noclober باعث میشود که نتوان در یک فایل overwrite کرد. البته میتوان با کمی تغییر دستور این overwrite را force کرد ولی این option بیشتر جنبه احتیاطی و هشدار دادن دارد. به مثال توجه کنید.
[root@CentOS6 ~]# ls > file1 [root@CentOS6 ~]# ls > file1 [root@CentOS6 ~]# ls > file1 // قبل از روشن کردن میتوان روی فایل قبلی نوشت [root@CentOS6 ~]# set -o noclobber [root@CentOS6 ~]# ls > file1 bash: file1: cannot overwrite existing file // خطا میدهد که نمیتوانید روی فایلی که محتوا دارد بنویسید [root@CentOS6 ~]# ls > file2 [root@CentOS6 ~]# ls > file2 bash: file2: cannot overwrite existing file [root@CentOS6 ~]# ls >| file2 // با گذاشتن یک پایپ این عمل نوشتن رو فایل را فورس کردم [root@CentOS6 ~]#
ضمیمه : دستور ls محتویات مسیری که هستیم را نشان میدهد. (امتحان کنید). یعنی نام فایل و ها پوشه های مسیری که در آنیم را نشان میدهد. با < خروجی این دستور رو ریختم تو یه فایل یه اسم مثلا file1 .... حالا با دستور cat file1 محتوبات این فایل را ببینید.
[root@CentOS6 ~]# ls a d file1 nohup.out proje.sh Templates VMwareTools-10.0.6-3595377.tar.gz anaconda-ks.cfg Desktop file2 Pictures Public test b Documents IFS post-install sfk Videos c Downloads Music post-install.log temp vm [root@CentOS6 ~]# ls > file1 [root@CentOS6 ~]# cat file1 a anaconda-ks.cfg b c d Desktop Documents Downloads file1 file2 IFS Music nohup.out Pictures post-install post-install.log proje.sh Public sfk temp Templates test Videos vm VMwareTools-10.0.6-3595377.tar.gz [root@CentOS6 ~]#
یکی از مهم ترین ویژگی های shell شاید alias باشد. alias نشان دهنده دستور است. برای اینکه یک دستور طولانی و یا پیچیده را بصورت کوتاه تر استفاده کنیم، برای آن یک alias نعریف میکنیم. alias مثل یک نام مستعار است. یک نام مستعار کوتاه تر و قابل یادآوری که به جای دستور طولانی یا پیچیده مینشیند. alias در حافظه موقت سیستم ذخیره میشود و با هر بار reboot سیستم مجبوریم آن را دوباره تعریف کنیم مگر اینکه آنرا ذخیره دائمی کرده باشیم. alias قبل از اینکه مسیر PATH برای هر کاربر پردازش شود، چک میشود. یکی از alias های پیش فرض سیستم، دستور ls است. در ترمینال خود type ls را وارد کنید. میبینید که دستور ls در حقیقت یک alias از دستور ls با سویچ اضافه است. به کد های زیر دقت کنید (اگه کد رو کپی میکردم رنگش نمی افتاد.)
در خط اول از دستور ls استفاده کردیم. محتویات درون مسیری که هستیم را نشان میدهد. رنگ آبی نشان دهنده مسیر است. رنگ سیاه یعنی فایل است. اگر هم فایل exe میداشتم سبز نشون میداد. سویچ F- نشان میدهد که جنس خروجی چیست. مثلا اگر directory باشد یک / میگذارد. اگر بخواهیم که دستور در حالت عادی اجرا شود و از alias استفاده نشود، قبل دستور یک \ میگذاریم. میبینید که وقتی \ گذاشتنم دیگه رنگی نشون نمیده. برای دیدن alias ها در ترمینال واژه alias را وارد کنید. لیستی مانند زیر نمایش داده خواهد شد.
حال میخواهم خودم یک alias ایجاد کنم. کلمه alias را مینویسم، سپس کلمه ای که به عنوان alias در نظر دارم. بعد از آن مساوی و درون ' ' دستور اصلی را وارد میکنم.
[root@CentOS6 /]# alias la='ls -al --color=auto' [root@CentOS6 /]# type la la is aliased to `ls -al --color=auto'
توجه داشته باشید که بصورت پیش فرض در همین ترمینال که هستم فقط این la تعریف شده است. برای از بین بردن alias هم از دستور unalias و نام alias استفاده کنید.
[root@CentOS6 ~]# alias la='ls -al --color=auto' [root@CentOS6 ~]# alias alias cp='cp -i' alias l.='ls -d .* --color=auto' alias la='ls -al --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde' [root@CentOS6 ~]# unalias la [root@CentOS6 ~]# alias alias cp='cp -i' alias l.='ls -d .* --color=auto' alias ll='ls -l --color=auto' alias ls='ls --color=auto' alias mv='mv -i' alias rm='rm -i' alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde' [root@CentOS6 ~]#
حاا این تنظیمات alias کجا ذخیره میشود؟؟ اگر شما هم مثل من از centos و یا یکی از توزیع های Red Hat استفاده میکنید، در مسیر home directory هر کاربر ( حتی root ) یک فایل به نام bashrc. وجود دارد. این فایل را باز کنید (با دستور cat) تا alias های دائمی را ببینید. برای اینکه یک alias همیشگی شود، آنرا در این فایل بنویسید. میتوانید از vim و یا gedit برای ویرایش این فایل استفاده کنید. با دستور ( vim .bashrc یا gedit .bashrc )
[root@CentOS6 ~]# whoami root [root@CentOS6 ~]# pwd /root [root@CentOS6 ~]# cat .bashrc # .bashrc # User specific aliases and functions alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi [root@CentOS6 ~]# [root@CentOS6 ~]# cd /home/mohammad/ [root@CentOS6 mohammad]# cat .bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # User specific aliases and functions [root@CentOS6 mohammad]#
همانطور که در شکل مشخص است برای root سه تا alias پیش فرض وجود دارد ولی برای کاربر mohammad هنوز هیچ alias ثبت نشده است. ( فایل هایی مثل bashrc. که قبلشان نقطه است، اصطلاحا فایل های سیستمی هستند. ) تمرین : برای یک کاربر غیر از root یک alias درست کرده و برای همیشه آنرا ذخیره کنید. میتوانید از دستور << برای اضافه کردن ( append کردن) به انتهای فایل bashrc. استفاده کنید.
همانطور که کمی در قسمت قبل اشاره کردیم، برای اینکه Alias ها از بین نروند باید آنها را در bashrc. ذخیره کرد. در کل 2 فایل وجود دارد که این اطلاعات environment (منظور محیطی که توش هستیم) را نگه میدارد. اصطلاحا به این 2 فایل "Login Scripts" گفته میشود. با یکی از آنها آشنا شدیم که bashrc. نام دارد. دیگری bash_profile. نام دارد که این فایل هم در hone directory هر کاربر قرار دارد.
حال هر کدام چه نقشی بازی میکنند؟ bash_profile. ===>> این فایل فقط یک بار آن هم در هنگام log in خوانده میشود. میتواند به PATH هر کاربر Append شود. bashrc. ===>> هر بار که یک bash جدید باز میکنیم، خوانده میشود. برای تعریف متغیر ها و یا شخصی سازی prompt میتوان از آن استفاده کرد. به دستورات زیر دقت کنید.
[root@CentOS6 mohammad]# pwd /home/mohammad [root@CentOS6 mohammad]# ls -a .bash* .bash_history .bash_logout .bash_profile .bashrc [root@CentOS6 mohammad]#
بیایید نگاهی به محتویات bash_profile. بیندازیم.
[mohammad@CentOS6 ~]$ echo $HOME /home/mohammad [mohammad@CentOS6 ~]$ pwd /home/mohammad [mohammad@CentOS6 ~]$ cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin export PATH [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$
دلیل اینکه این فایل یک بار خوانده میشود این است که وقتی کاربر وارد شد، برای او یک متغیر PATH تنظیم میشود. یک الگوی ثابت برای PATH وجود دارد و برای هر کاربر از این الگوی ثابت به اضافه مسیر bin که در home directory کاربر وجود دارد استفاده میشود. دقت کنید که متغیر PATH برابر مقدار پیش فرض خود به اضافه HOMEbin$ شده. منطقش اینه که PATH برابر خودش ( PATH=$PATH ) ، به اضافه HOME/bin$ که مقدار HOME$ را میبینید. از : برای جدا کردن مقادیر PATH استفاده میشود. شاید ندانید PATH چیست. در واقع PATH آدرس تمام دستوراتی است که یک کاربر میتواند اجرا کند، شامل کتابخانه ها و ... .
[mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$ echo $PATH /usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/mohammad/bin [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$
به قسمت آخر PATH دقت کنید. اوت تیکه رو فایل bash-profile. درست کرده. این تعریف PATH فقط یکبار اتفاق میفته برای همین توی bash-profile. نوشته شده. اگه دوباره bash-profile. اجرا بشه، الکی طول این PATH زیاد میشه. ( شاید مشکلات دیگه ای هم باشه که من نمیدونم ). در قسمت بالای bash-profile. هم چک میکند که اگر bashrc. وجود دارد آنرا اجرا کند. برای همین بیشتر تنظیمات shell را در bashrc. میگذاریم. حال یه نگاهی هم به bashrc. بیندازیم.
[mohammad@CentOS6 ~]$ cat .bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # User specific aliases and functions [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$
در قسمت بالای فایل ابتدا چک میکند که آیا فایل bashrc. سراسری وجود دارد یا نه، اگر باشد آنرا میخواند. bashrc. سراسری برای تنظیمات shell همه کاربران است. برای همین در مسیر etc قرار دارد. مثلا اگر بخواهیم یک alias برای همه کاربران تعریف شود، آنرا در bashrc.
سراسری واقع در پوشه etc تعریف میکنیم. یا مثلا اگر خواستیم که هیچ کاربری نتواند هیچ فایلی را overwrite کند دستورش را در bashrc. سراسری وارد میکنیم. حال اگر خواستیم فایل bashrc. دوباره خوانده شود، مثلا تغییراتی در آن داده ایم، از یکی از 2 دستور زیر استفاده کنید. ممکن است هشداری مبنی بر تنظیمات جدید در سیستم دهد.
[mohammad@CentOS6 ~]$ . .bashrc [mohammad@CentOS6 ~]$ source .bashrc
مثلا :
[mohammad@CentOS6 ~]$ echo "set -o noclobber" >> .bashrc [mohammad@CentOS6 ~]$ source .bashrc [mohammad@CentOS6 ~]$ cat .bashrc # .bashrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi # User specific aliases and functions set -o noclobber [mohammad@CentOS6 ~]$ ls > file1 [mohammad@CentOS6 ~]$ ls > file1 -bash: file1: cannot overwrite existing file [mohammad@CentOS6 ~]$
در این بخش به بررسی اصول نوشتن Shell Script در لینوکس میپردازیم. برای نوشتن یک برنامه تحت Shell به نکات زیر توجه کنید.
موارد بالا برای نوشتن هر نوع برنامه ای به هر زبانی در لینوکس است. چه پایتون، چه C، چه پرل و ... بریم سراغ اصل کار. به کد های زیر توجه کنید. برای کاربری که با نام آن وارد سیستم شدم، متغیر PATH را نگاه میکنم، قسمت آخر متغیر PATH را نگاه کنید. همان قسمتی بود که توسط bash-profile ایجاد شده بود. این مسیر بطور پیش فرض وجود ندارد. یعنی نمیتوانم به آن cd کنم ولی در PATH وجود دارد.
یعنی هر بار که دستوری زده میشود، این مسیر هم توسط سیستم عامل چک میشود. میتوان این پوشه را با دستور mkdir درست کرد. راحت تر است که برای نوشتن برنامه ها از این مسیر استفاده کنیم و فایل های برنامه را اینجا ذخیره کنیم، چون بصورت پیش قرض در PATH وجود داردو هر جای دیگر هم میتوان برنامه ها را ذخیره کرد. میتوان هر مسیری را هم به PATH اضافه کرد. این کاملا به شما بستگی دارد. فقط همانطور که گفتم اگر مسیر برنامه در PATH باشد، در هر مسیری قایل اجراست ولی اگر مسیر برنامه در PATH نباشد، برای اجرای آن باید آدرس absolute (یعنی آدرس از ریشه) بدهیم.
[mohammad@CentOS6 ~]$ pwd /home/mohammad [mohammad@CentOS6 ~]$ echo $PATH /usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/mohammad/bin [mohammad@CentOS6 ~]$ cd bin -bash: cd: bin: No such file or directory [mohammad@CentOS6 ~]$ mkdir bin [mohammad@CentOS6 ~]$ cd bin [mohammad@CentOS6 bin]$ pwd /home/mohammad/bin //برنامه ها را اینجا ذخیره میکنیم [mohammad@CentOS6 bin]$
بسیار خوب ، بیاید یم مثال ساده رو اجرا کنیم. به کد زیر دقت کنید.
[mohammad@CentOS6 bin]$ vim hello.sh [mohammad@CentOS6 bin]$ ls -l hello.sh -rw-rw-r--. 1 mohammad mohammad 44 Aug 18 13:45 hello.sh [mohammad@CentOS6 bin]$ chmod +x hello.sh [mohammad@CentOS6 bin]$ hello.sh We are ITPRO!!! [mohammad@CentOS6 bin]$ ls -l hello.sh -rwxrwxr-x. 1 mohammad mohammad 44 Aug 18 13:45 hello.sh [mohammad@CentOS6 bin]$ cd ~ [mohammad@CentOS6 ~]$ hello.sh We are ITPRO!!! [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$ bash -x bin/hello.sh + echo 'We are ITPRO!!!' We are ITPRO!!! + exit 0 [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$
در همان مسیری که بودم با استفاده از vim یا gedit یک سند خالی درست کردم. درون آن کد ها زیر را وارد کردم.
#!/bin/bash echo "We are ITPRO!!!" exit 0
در خط اول به سیستم عامل میگوییم برای خواندن و اجرای برنامه از چه کتابخانه ای استفاده کند. مسیر نصب bash را وارد کردم. اگر داشتم پایتون مینوشتم مسیر نصب پایتون رو میدادم. خط بعد با دستور echo یک جمله را در خروجی چاپ کردم. در خط آخر هم گفتم 0 را برگردان. 0 به معنی اجرای صحیح برنامه است.
سپس برنامه را ذخیره کرده و خارج میشم. اگر با دستور ls جزئیات فایل hello.sh را چاپ کنم، متوجه میشوم که خاصیت exe یعنی خاصیت اجرایی ندارد. با دستور chmod این فایل را exe میکنم تا از حالت فقط متنی خارج شود. حالا اگر نام برنامه را بزنم، برنامه اجرا میشود. حتی اگر مسیرم را با دستور cd عوض کنم باز هم برنامه اجرا میشود. برای debug کردن یک برنامه از دستور bash و سویچ x- استفاده کنید.
مسلما ما فقط نمی خواهیم که برنامه یک رشته از قبل تعریف شده را چاپ کند. برنامه ما باید بتواند ورودی هم بگیرد. برای خواندن ورودی میتوان از 2 روش کلی استفاده کرد:
دستور read دقیقا مثل دستور scanf در C و یا cin در ++C است. این دستور مقداری را از صفحه کلید کاربر میگیرد. به مثال ساده زیر توجه کنید. همان سندی که جلسه قبل ایجاد کردید را با vim یا gedit باز کنید و کد های زیر را درون آن بنویسید.
#!/bin/bash echo -e "Enter your name: \c" read INPUT_NAME echo "Hello $INPUT_NAME" exit 0
خروجی بصوزت زیر خواهد بود:
[mohammad@CentOS6 bin]$ hello.sh Enter your name: Mohammad Hello Mohammad
دستور echo را با سویچ e- وارد کردیم و یک c\ گداشتیم. اگر از کاراکتر های خاص مثل c\ استفاده میکنیم باید e- بگذاریم. با این c\ برنامه تا زمان گرفتن ورودی جلو تر نمی رود. ( به صفحه manual این دستور مراجعه کنید. توضیح بیشترم نمیاد !!! ) با دستور read ورودی را از کاربر گرفته و درون یک متغیر میریزد. در آخر هم یک رشته را با متغیر پر شده توسط کاربر چاپ کردیم.
خوب برویم سراغ روش دوم. به تصویر زیر دقت کنید. وقتی که نام یک اسکریپت را در ترمینال برای اجرا میزنید، عباراتی که جلوی آن مینویسید، حکم آرگومان ارسالی برای برنامه را دارند. به ترتیب از یک این آرگومان ها شماره میگیرند و در برنامه میتوان آنها را استفاده کرد.
به قطعه کد زیر دقت کنید، همان سند قبلی را اینطور تغییر دادم:
#!/bin/bash echo "This is 1st arg: $1" echo "This is 2nd arg: $2" echo "This is 3rd arg: $3" echo "This is 4th arg: $4" echo "This is 5th arg: $5" echo "This is 6th arg: $6" echo "This is Script's name: $0" exit 0
حالا من 6 تا آرگومان نوشتم، شما بیشتر هم میتونید استفاه کنید. حالا برای پاس دادن مقادیر به برنامه، عبارات را در مقابل نام برنامه وارد میکنیم.
[mohammad@CentOS6 bin]$ hello.sh centos redhat mint kali debian arch This is 1st arg: centos This is 2nd arg: redhat This is 3rd arg: mint This is 4th arg: kali This is 5th arg: debian This is 6th arg: arch This is Script's name: /home/mohammad/bin/hello.sh [mohammad@CentOS6 bin]$
مطلب بسیار ساده است. سعی کنید برای خود مثال های بیشتری طراحی کنید. حالا بیاید یک نکته ریز را بررسی کنیم. #$ و @$ هر دو مقادیر آرگومانها را نگه میدارند. ولی تفاوت آنها در چیست؟؟ مثال زیر را ببینید. در حقیقت *$ یک single string است. در حالی که #$ یک آرایه ( array ) است.
#!/bin/bash echo "This is counts of parameters: $#" echo "Using \"\$*\":" for a in "$*"; do echo ">"$a; done echo -e "\nUsing \$*:" for a in $*; do echo ">"$a; done echo -e "\nUsing \"\$@\":" for a in "$@"; do echo ">"$a; done echo -e "\nUsing \$@:" for a in $@; do echo ">"$a; done exit 0
حال اگر به این برنامه ورودی بدهیم:
[mohammad@CentOS6 bin]$ hello.sh one two three "four five" six This is counts of parameters: 5 Using "$*": >one two three four five six Using $*: >one >two >three >four >five >six Using "$@": >one >two >three >four five >six Using $@: >one >two >three >four >five >six [mohammad@CentOS6 bin]$
فکر میکنم جای توضیح ندارد. فقط از حلقه for استفاده کردم. ساختار for به این صورت است که گفته به ازای تک تک مقادیر #$ یا *$ ، مقدار آنها درون a ریخته شود، درون بدنه for این متغیر a را چاپ کردم. مثلا میتوانید خروجی هر دستوری را وارد حلقه for کنید. مثلا اگر من بزنم `for var in `ls درون حلقه for مقدار متغیر var برابر با هر خط خروجی دستور ls خواهد بود. مثلا اگه بخوام روی همه فایل های یک پوشه کاری انجام بدم از این روش میشه استفاده کرد. منظورم یه همچین چیزیه:
for var in `ls` do echo $var done
مثلا این الان محتوبات داخل مسیر رو نشون میده.
در این جلسه در مورد ساختار شرط if صبت میکنیم. منطق if در زبان های برنامه نویسی مختلف یکسان است. یک یا چند شرط به عنوان ورودی به if میدیهم، اگر برقرار باشند یا نباشند دستورات خاصی اجرا میشود. به قطعه کد زیر دقت کنید.
#!/bin/bash if (( $# < 1 )) then echo "Usage : $0 <name> " exit 1 fi echo "Hello $1" exit 0
این شرط چک میکند که آیا هیچ پارامتری به برنامه ارسال شده یانه ؟؟ اگر پارامتری ارسال نشده، پیامی میدهد و با کد خطا از برنامه خارج میشود. در عیر این صورت ادامه برنامه اجرا میشود. اون fi به معنای خاتمه قطعه کد if است.
[mohammad@CentOS6 bin]$ if.sh Mohammad Hello Mohammad [mohammad@CentOS6 bin]$ if.sh Usage : /home/mohammad/bin/if.sh <name> [mohammad@CentOS6 bin]$
راستش انقدر if پیج و خم داره که فک کنم بشه واسش به دوره جدا کامل نوشت. یه کوچولو اینجا مبحثشو باز میکنیم، بقیشو خودتون مطالعه کنید.
دستور if اسنفاده بسیار گسترده ای داره، مثلا برای چک کردن اینکه یک فایل وجود دارد یا خیر و یا اینکه قایبل خواندن است یا خیر از نمونه کئ زیر استفاده میکنیم.
if [ -r somefile ]; then content=$(cat somefile) elif [ -f somefile ]; then echo “The file ‘somefile’ exists but is not readable to the script.” else echo “The file ‘somefile’ does not exist.” fi
کد بالا ابتدا با سویچ r- چک میکند که فایل قابل خواندن ( readable ) هست یا نه. با سویچ f- چک میکند که فایل وجود دارد یا نه. در شرط اول، اگر برقرار باشد، فایل را باز میکند و درون متغیر content میریزد.
برای چک کردن محتوای یک متغیر و مقایسه مقدار آن از سویچ های زیر استفاده کنید.
حالا یه سری مثال با اینا ببینید:
value=$( grep -ic "Mohammad" /etc/passwd ) if [ $value -eq 1 ] then echo "I found Mohammad" else echo "I didn't find Mohammad" fi
value=$( grep -ic "Mohammad" /etc/passwd ) if [ $value -eq 1 ] then echo "I found one Mohammad" elif [ $value -gt 1 ] then echo "I found multiple Mohammad" else echo "I didn't find any Mohammad" fi
read -p "Enter value of i :" i if [ $i -eq 10 ] then echo "Value of i is 10" else echo "Value of i is not equal to 10" fi
read -p "Enter value of i :" i read -p "Enter value of j :" j read -p "Enter value of k :" k if [ $i -gt $j ] then if [ $i -gt $k ] then echo "i is greatest" else echo "k is greatest" fi else if [ $j -gt $k ] then echo "j is greatest" else echo "k is greatest" fi fi
حالا مثال های خیلی متنوعی میشه ساخت از اینا. جدول زیر یه دید کلی از سویج های if نشون میده.
File tests Operator syntax Description -a <FILE> True if <FILE> exists. :!: (not recommended, may collide with -a for AND, see below) -e <FILE> True if <FILE> exists. -f <FILE> True, if <FILE> exists and is a regular file. -d <FILE> True, if <FILE> exists and is a directory. -c <FILE> True, if <FILE> exists and is a character special file. -b <FILE> True, if <FILE> exists and is a block special file. -p <FILE> True, if <FILE> exists and is a named pipe (FIFO). -S <FILE> True, if <FILE> exists and is a socket file. -L <FILE> True, if <FILE> exists and is a symbolic link. -h <FILE> True, if <FILE> exists and is a symbolic link. -g <FILE> True, if <FILE> exists and has sgid bit set. -u <FILE> True, if <FILE> exists and has suid bit set. -r <FILE> True, if <FILE> exists and is readable. -w <FILE> True, if <FILE> exists and is writable. -x <FILE> True, if <FILE> exists and is executable. -s <FILE> True, if <FILE> exists and has size bigger than 0 (not empty). -t <fd> True, if file descriptor <fd> is open and refers to a terminal. <FILE1> -nt <FILE2> True, if <FILE1> is newer than <FILE2> (mtime). :!: <FILE1> -ot <FILE2> True, if <FILE1> is older than <FILE2> (mtime). :!: <FILE1> -ef <FILE2> True, if <FILE1> and <FILE2> refer to the same device and inode numbers. :!: String tests Operator syntax Description -z <STRING> True, if <STRING> is empty. -n <STRING> True, if <STRING> is not empty (this is the default operation). <STRING1> = <STRING2> True, if the strings are equal. <STRING1> != <STRING2> True, if the strings are not equal. <STRING1> < <STRING2> True if <STRING1> sorts before <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use \< <STRING1> > <STRING2> True if <STRING1> sorts after <STRING2> lexicographically (pure ASCII, not current locale!). Remember to escape! Use \> Arithmetic tests Operator syntax Description <INTEGER1> -eq <INTEGER2> True, if the integers are equal. <INTEGER1> -ne <INTEGER2> True, if the integers are NOT equal. <INTEGER1> -le <INTEGER2> True, if the first integer is less than or equal second one. <INTEGER1> -ge <INTEGER2> True, if the first integer is greater than or equal second one. <INTEGER1> -lt <INTEGER2> True, if the first integer is less than second one. <INTEGER1> -gt <INTEGER2> True, if the first integer is greater than second one. Misc syntax Operator syntax Description <TEST1> -a <TEST2> True, if <TEST1> and <TEST2> are true (AND). Note that -a also may be used as a file test (see above) <TEST1> -o <TEST2> True, if either <TEST1> or <TEST2> is true (OR). ! <TEST> True, if <TEST> is false (NOT). ( <TEST> ) Group a test (for precedence). Attention: In normal shell-usage, the "(" and ")" must be escaped; use "\(" and "\)"! -o <OPTION_NAME> True, if the shell option <OPTION_NAME> is set. -v <VARIABLENAME> True if the variable <VARIABLENAME> has been set. Use var[n] for array elements. -R <VARIABLENAME> True if the variable <VARIABLENAME> has been set and is a nameref variable (since 4.3-alpha)
برای استفاده از امکان AND و OR کردن شرط ها با هم بهتر است از || به معنی AND و && به معنی OR استفاده کنید.
if [[ condition1 ]] && [[ condition2 ]]; then //OR "do something" fi if [[ condition1 ]] || [[ condition2 ]]; then //AND "do something" fi if [[ condition1 ]] && [[ condition2 ]] || [[ condition3 ]] && [[ condition4 ]] ; then //OR + AND "do something" fi
شاید دیده باشید که بعضی جاها در if از [ ] یا [[ ]] یا (( )) یا ( ) استفاده میکنند. هر کدام از اینا استفاده خاص خود را دارند.
1- [ ]
برای کار با "رشته ها" و "فایل ها" و "مقایسه و محاسبات ریاضی"
2- [[ ]]
خاصیت های [ ] را دارد ولی بهبود یافته آن است. تفاوت های کوچک کلیدی با هم دارند. بررسی تفاوت ها از حوصله این جلسه خیلی خارجه !!!
3- (( ))
بیشتر برای مقایسه ریاضی استفاده میشود. این از korn shell گرفته شده.
ضمیمه : دلم نمیاد مورد دوم رو بدون مثال ولش کنم!!! مثلا اینو ببینید:
if [ -a *.sh ]; then
اگه از همچین فایلی "یکی" وجود داشته باشه true برمیگردونه و اگه اصلا وجود نداشته باشه false برمیگردونه، اگه بیشتر از یکی وجود داشته باشه error میده کلا برنامه !!! برای همین در این مورد باید از این یکی استفاده کنیم که اگه چند تا فایل وجود داشت بتونه تشخیص بده:
if [[ -a *.sh ]]; then
همانطور که گفتم دستور if واسه خودش یه دورس... یه اشاره کوچیکی ازش اینجا کردیم.
هنگامی که قرار است برای یک ورودی مقادیر مختلفی چک شود و به ازای هر مقدار آن تصمیم خاصی گرفته شود، از case استفاده میکنیم. case یک if توسعه یافته است. منطق case در زبان های برنامه نویسی مختلف یکسان است. به ساختار زیر دقت کنید.
یک مثال نسبتا ساده را از case در bash بررسی میکنیم. به کد زیر دقت کنید.
#!/bin/bash if [[ ! -d $1 ]] then echo "Usage: $0 <directory>" exit 1 fi case $2 in "directory") find $1 -maxdepth 1 -type d ;; "link") find $1 -maxdepth 1 -type l ;; *) echo "Usage: $0 <directory> directory | link " ;; esac exit 0
صورت مساله این است که برنامه ای بنویسید که یک مسیر بگیرد، سپس بر اساس اعلام کاربر به دنبال پوشه ها و یا لینک ها در این مسیر تا عمق یکی باشد.
اول از همه با دستور if بررسی میکند که آیا آرگومان اول ارسالی یک مسیر هست یا نه. علامت ! ینی نقیض. پس خط اول میشه اگه آرگومان اول یک directory نیست یک پیام چاپ کن و با کد خطا از برنامه خارج شو. اگر آرگومان اول یک مسیر باشد، شرط برقرار نمیشود و وارد بدنه دستور if نمیشود و برنامه ادامه میابد. بعد از آن از ساختار case برای تشخیص آرگومان ارسالی دوم استفاده کردیم. این case تصمیم میگیرد که با توجه به مقدار آرگومان دوم، چه دستوراتی اجرا شود. در حالت اول اگر مقدار آرگومان دوم directory باشد قطعه کئ زیر آن اجرا میشود. در حالت دوم هم اگر مقدار آرگومان دوم link باشد قطعه کد زیر آن اجرا میشود. مورد آخر که با ستاره مشخص شده یعنی حالت پیش فرض است اگر هیچ یک از سرایط بالا برقرار نباشد، قطعه کد درون ستاره اجرا میشود.
خروجی بصورت زیر است، حالت هایی که خطا میدهد را هم امتحان کردیم.
[mohammad@CentOS6 ~]$ case.sh Usage: /home/mohammad/bin/case.sh <directory> [mohammad@CentOS6 ~]$ case.sh /etc Usage: /home/mohammad/bin/case.sh <directory> directory | link [mohammad@CentOS6 ~]$ case.sh /etc link /etc/grub.conf /etc/rc1.d /etc/redhat-release /etc/favicon.png /etc/rc6.d /etc/rc2.d /etc/init.d /etc/rc.local /etc/rc4.d /etc/rc5.d /etc/rc /etc/rc3.d /etc/system-release /etc/rc0.d /etc/rc.sysinit [mohammad@CentOS6 ~]$ case.sh /etc directory /etc /etc/rpm /etc/iproute2 /etc/iscsi /etc/xml /etc/sound /etc/profile.d /etc/festival /etc/ssh /etc/ld.so.conf.d /etc/setuptool.d /etc/reader.conf.d /etc/request-key.d /etc/cups /etc/rsyslog.d /etc/chkconfig.d /etc/alternatives /etc/event.d /etc/spice /etc/cron.weekly /etc/libvirt /etc/popt.d /etc/skel /etc/bluetooth /etc/pcmcia /etc/logrotate.d /etc/NetworkManager /etc/ntp /etc/pulse /etc/cron.monthly /etc/dhcp /etc/samba /etc/default /etc/gnupg /etc/rpmdevtools /etc/selinux /etc/PackageKit /etc/vmware-tools /etc/makedev.d /etc/named /etc/fcoe /etc/sasl2 /etc/sudoers.d /etc/udev /etc/security /etc/prelink.conf.d /etc/bash_completion.d /etc/ssl /etc/modprobe.d /etc/hal /etc/sysconfig /etc/blkid /etc/X11 /etc/acpi /etc/rwtab.d /etc/opt /etc/pm /etc/xdg /etc/pam.d /etc/libreport /etc/gtk-2.0 /etc/sgml /etc/yum /etc/init /etc/postfix /etc/statetab.d /etc/ghostscript /etc/gnome-vfs-2.0 /etc/ConsoleKit /etc/dnsmasq.d /etc/foomatic /etc/plymouth /etc/scl /etc/gcrypt /etc/rc.d /etc/dracut.conf.d /etc/yum.repos.d /etc/httpd /etc/pango /etc/audit /etc/dbus-1 /etc/portreserve /etc/pki /etc/polkit-1 /etc/gdm /etc/xinetd.d /etc/cron.d /etc/cron.daily /etc/avahi /etc/audisp /etc/terminfo /etc/bonobo-activation /etc/gconf /etc/cron.hourly /etc/obex-data-server /etc/fonts /etc/vmware-caf /etc/lvm /etc/depmod.d /etc/wpa_supplicant /etc/ppp /etc/kdump-adv-conf /etc/openldap /etc/alsa /etc/lsb-release.d /etc/multipath [mohammad@CentOS6 ~]$
بسیار خوب. این یک مثال برای درک مطلب بود. سعی کنید کمی خلاقیت به خرج بدین و مثال بسازید. مثلا case رو با دستور read ترکیب کنید که case بر اساس متغیر هایی که بوسیله دستور read از کاربر گرفته میشود، تصمیم گیری کند.
در این جلسه در مورد حلقه ها در bash صحبت میکنیم. حلقه ها در برنامه نویسی بسیار پرکاربرد هستند. انواع مختلفی از حلقه ها در bash وجود دارد.
1- حلقه for
2- حلقه until
3- حلقه while
قبل از اینکه وارد مبحث حلقه ها بشیم به نکته کوچیک بگم. توی چند قسمت گذشته توی مثال ها دیدید که بعضی وقت ها خروجی یک دستور رو میریختیم توی یه متغیر. این کار به 2 صورت انجام میشه.
راه اول: گذاشتن دستور داخل back quotation و برابر یک مقدار قرار دادن. مثلا خروجی دستور ls را درون متغیر var ریختیم
[root@CentOS6 boot]# var=`ls` [root@CentOS6 boot]# echo $var config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686 [root@CentOS6 boot]# ls config-2.6.32-279.el6.i686 grub memtest86+-4.10 vmlinuz-2.6.32-279.el6.i686 efi initramfs-2.6.32-279.el6.i686.img symvers-2.6.32-279.el6.i686.gz elf-memtest86+-4.10 lost+found System.map-2.6.32-279.el6.i686 [root@CentOS6 boot]#
راه دوم : دستور را داخل ()$ گذاشتن و برابر یک متغیر قرار دادن:
[root@CentOS6 boot]# var=$(ls) [root@CentOS6 boot]# echo $var config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686 [root@CentOS6 boot]# ls config-2.6.32-279.el6.i686 grub memtest86+-4.10 vmlinuz-2.6.32-279.el6.i686 efi initramfs-2.6.32-279.el6.i686.img symvers-2.6.32-279.el6.i686.gz elf-memtest86+-4.10 lost+found System.map-2.6.32-279.el6.i686 [root@CentOS6 boot]#
برگردیم سر حلقه ها. از حلقه for که قبلا هم در مثال ها استفاده کردیم. کد ساده زیر رو ببینید. برای نوشتن برنامه حتما لازم نیست توی یه فایل متنی نوشته بشن. توی خود ترمینال هم میتونید دستورات رو وارد کنید.
[root@CentOS6 ~]# for i in `seq 10` > do > echo $i > sleep 1 > done 1 2 3 4 5 6 7 8 9 10 [root@CentOS6 ~]#
دستور seq تا عدد مقابل آن میشمارد. در اینجا هر بار که دستور seq یک عدد تولید میکند، مقدار i برابر این مقدار میشود. دستورات حلقه for درون do و done نوشته میشود. دقت داشته باشید که seq 10 رو داخل back quotation نوشتم. بزارید یه مثال ساده دیگه هم ببینیم.
[root@CentOS6 /]# for i in $(ls) > do > echo -e "item: $i \n" > done item: bin item: boot item: dev item: etc item: file1 item: file2 item: home item: lib item: lost+found item: media item: misc item: mnt item: net item: opt item: proc item: root item: sbin item: selinux item: srv item: sys item: tmp item: usr item: var [root@CentOS6 /]#
حالا بریم سراغ حلقه while. مثال ساده زیر را ببینید. تا زمانی که شرط حلقه while برقرار باشد، دستورات داخل آن اجرا میشوند.
[root@CentOS6 /]# count=0 [root@CentOS6 /]# while [ $count -lt 10 ] > do > echo count is $count > let count=count+1 > done count is 0 count is 1 count is 2 count is 3 count is 4 count is 5 count is 6 count is 7 count is 8 count is 9 [root@CentOS6 /]#
واسه اینکه یکم ذهنتون درگیر بشه برید سرچ کنید که چرا وقتی دستور for یا while رو میزنیم شکل prompt میشه < و اسم این حالتی که فعال میشه چیه و آیا میشه تغییرش داد یا نه. سر کاری نیستا !!!! :)))) شاید اینجوری یکی یه کامنتی بزاره زیر پستا !!!
دستور until هم بصورت زیره، فقط دقت داشته باشید که شرطی که به until میدهیم ، شرط اتمام حلقه است.
[root@CentOS6 /]# counter=1 [root@CentOS6 /]# until [ $counter -gt 10 ] > do > echo $counter > ((counter++)) > done 1 2 3 4 5 6 7 8 9 10 [root@CentOS6 /]#
حالا یه مدل دیگه هم for داریم که مث for توی خانواده c میمونه:
[root@CentOS6 /]# for ((i=0;i<10;i+=1)) > do > echo $i > done 0 1 2 3 4 5 6 7 8 9 [root@CentOS6 /]#
اینم ببینید جالبه. یعنی از 0 شروع کن و تا 25 برو. قدم هاتم 5 تایی باشه
[root@CentOS6 /]# for i in {0..25..5} > do > echo $i > done 0 5 10 15 20 25 [root@CentOS6 /]#
مثال یکم سخت تر: برنامه ای ینویسید که یک عدد از کاربر بگیرد و به همان تعداد عدد اول چاپ کند.
#!/bin/bash read -p "How many prime numbers ?: " num c=0 k=0 n=2 echo 1 numero=$[$num-1] while [ $k -ne $num ]; do for i in `seq 1 $n`;do r=$[$n%$i] if [ $r -eq 0 ]; then c=$[$c+1] fi done if [ $c -eq 2 ]; then echo "$i" k=$[$k+1] fi n=$[$n+1] c=0 done
[root@CentOS6 ~]# ./prime.sh How many prime numbers ?: 3 1 2 3 5 [root@CentOS6 ~]# ./prime.sh How many prime numbers ?: 5 1 2 3 5 7 11 [root@CentOS6 ~]# ./prime.sh How many prime numbers ?: 15 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 [root@CentOS6 ~]#
در این جلسه در مورد حلقه ها در bash صحبت میکنیم. حلقه ها در برنامه نویسی بسیار پرکاربرد هستند. انواع مختلفی از حلقه ها در bash وجود دارد.
1- حلقه for
2- حلقه until
3- حلقه while
قبل از اینکه وارد مبحث حلقه ها بشیم به نکته کوچیک بگم. توی چند قسمت گذشته توی مثال ها دیدید که بعضی وقت ها خروجی یک دستور رو میریختیم توی یه متغیر. این کار به 2 صورت انجام میشه.
راه اول: گذاشتن دستور داخل back quotation و برابر یک مقدار قرار دادن. مثلا خروجی دستور ls را درون متغیر var ریختیم
[root@CentOS6 boot]# var=`ls` [root@CentOS6 boot]# echo $var config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686 [root@CentOS6 boot]# ls config-2.6.32-279.el6.i686 grub memtest86+-4.10 vmlinuz-2.6.32-279.el6.i686 efi initramfs-2.6.32-279.el6.i686.img symvers-2.6.32-279.el6.i686.gz elf-memtest86+-4.10 lost+found System.map-2.6.32-279.el6.i686 [root@CentOS6 boot]#
راه دوم : دستور را داخل ()$ گذاشتن و برابر یک متغیر قرار دادن:
[root@CentOS6 boot]# var=$(ls) [root@CentOS6 boot]# echo $var config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686 [root@CentOS6 boot]# ls config-2.6.32-279.el6.i686 grub memtest86+-4.10 vmlinuz-2.6.32-279.el6.i686 efi initramfs-2.6.32-279.el6.i686.img symvers-2.6.32-279.el6.i686.gz elf-memtest86+-4.10 lost+found System.map-2.6.32-279.el6.i686 [root@CentOS6 boot]#
برگردیم سر حلقه ها. از حلقه for که قبلا هم در مثال ها استفاده کردیم. کد ساده زیر رو ببینید. برای نوشتن برنامه حتما لازم نیست توی یه فایل متنی نوشته بشن. توی خود ترمینال هم میتونید دستورات رو وارد کنید.
[root@CentOS6 ~]# for i in `seq 10` > do > echo $i > sleep 1 > done 1 2 3 4 5 6 7 8 9 10 [root@CentOS6 ~]#
دستور seq تا عدد مقابل آن میشمارد. در اینجا هر بار که دستور seq یک عدد تولید میکند، مقدار i برابر این مقدار میشود. دستورات حلقه for درون do و done نوشته میشود. دقت داشته باشید که seq 10 رو داخل back quotation نوشتم. بزارید یه مثال ساده دیگه هم ببینیم.
[root@CentOS6 /]# for i in $(ls) > do > echo -e "item: $i \n" > done item: bin item: boot item: dev item: etc item: file1 item: file2 item: home item: lib item: lost+found item: media item: misc item: mnt item: net item: opt item: proc item: root item: sbin item: selinux item: srv item: sys item: tmp item: usr item: var [root@CentOS6 /]#
حالا بریم سراغ حلقه while. مثال ساده زیر را ببینید. تا زمانی که شرط حلقه while برقرار باشد، دستورات داخل آن اجرا میشوند.
[root@CentOS6 /]# count=0 [root@CentOS6 /]# while [ $count -lt 10 ] > do > echo count is $count > let count=count+1 > done count is 0 count is 1 count is 2 count is 3 count is 4 count is 5 count is 6 count is 7 count is 8 count is 9 [root@CentOS6 /]#
واسه اینکه یکم ذهنتون درگیر بشه برید سرچ کنید که چرا وقتی دستور for یا while رو میزنیم شکل prompt میشه < و اسم این حالتی که فعال میشه چیه و آیا میشه تغییرش داد یا نه. سر کاری نیستا !!!! :)))) شاید اینجوری یکی یه کامنتی بزاره زیر پستا !!!
دستور until هم بصورت زیره، فقط دقت داشته باشید که شرطی که به until میدهیم ، شرط اتمام حلقه است.
[root@CentOS6 /]# counter=1 [root@CentOS6 /]# until [ $counter -gt 10 ] > do > echo $counter > ((counter++)) > done 1 2 3 4 5 6 7 8 9 10 [root@CentOS6 /]#
حالا یه مدل دیگه هم for داریم که مث for توی خانواده c میمونه:
[root@CentOS6 /]# for ((i=0;i<10;i+=1)) > do > echo $i > done 0 1 2 3 4 5 6 7 8 9 [root@CentOS6 /]#
اینم ببینید جالبه. یعنی از 0 شروع کن و تا 25 برو. قدم هاتم 5 تایی باشه
[root@CentOS6 /]# for i in {0..25..5} > do > echo $i > done 0 5 10 15 20 25 [root@CentOS6 /]#
مثال یکم سخت تر: برنامه ای ینویسید که یک عدد از کاربر بگیرد و به همان تعداد عدد اول چاپ کند.
#!/bin/bash read -p "How many prime numbers ?: " num c=0 k=0 n=2 echo 1 numero=$[$num-1] while [ $k -ne $num ]; do for i in `seq 1 $n`;do r=$[$n%$i] if [ $r -eq 0 ]; then c=$[$c+1] fi done if [ $c -eq 2 ]; then echo "$i" k=$[$k+1] fi n=$[$n+1] c=0 done
[root@CentOS6 ~]# ./prime.sh How many prime numbers ?: 3 1 2 3 5 [root@CentOS6 ~]# ./prime.sh How many prime numbers ?: 5 1 2 3 5 7 11 [root@CentOS6 ~]# ./prime.sh How many prime numbers ?: 15 1 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 [root@CentOS6 ~]#
در این قسمت درمورد مدیریت user ها و group ها در لینوکس صحبت میکنیم. درست کردن user ها در سیستم های لینوکسی یکی از کار های روتین مدیر سیستم است. ممکن است مدیر سیستم بخواهد یک یا چند کاربر را با مشخصاتی پیش فرض در سیستم درست کند. با حتی بخواهد یک یا چند کاربر با مشخصاتی غیر از پیش فرض در سیستم ایجاد کند. تنظیماتی پیش فرض در سیستم وجود دارد که اگر شما هنگام ایجاد یک کاربر، مشخصه خاصی تعیین نکنید، از این تنظیمات برای ایجاد کاربر استفاده میکند. مسیر این فایل تنظیمات بصورت زیر است.
[root@CentOS6 ~]# cat /etc/default/useradd # useradd defaults file GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/etc/skel CREATE-MAIL-SPOOL=yes [root@CentOS6 ~]#
شاید اگر این فایل را تا بحال ندیده باشید باز هم حدس زدن معنی بعضی از عناصر آن کار راحتی باشد. ولی بگذارید تک تک آنها را بررسی کنیم.
GROUP=100 : هنگامی که کاربر ایجاد شد مقدار group id او را برابر 100 قرار بده. ( چرا 100 ؟ )
HOME=home : آدرس home directory کاربر را از home شروع کن.
INACTIVE=-1 : عدد 1- یعنی disable است. این مشخصه یعنی اگر پسورد کاربر منقضی شد، کاربر تا چند روز فرصت دارد پسورد خود را عوض کند. در این مدت همان پسورد قدیمی او قابل استفاده است ولی اگر مدت تعیین شده به پایان رسد، کاربر قادر به ورود به سیستم نخواهد بود. مثلا اگر این مقدار برابر 4 باشد یعنی کاربر 4 روز فرصت دارد و بعد از آن اگر رمز را عوض نکرده باشد دیگر اجازه ورود ندارد.
EXPIRE= : اگر میخواهید اکانت کاربر پس از مدت مشخصی از بین برود، به این مشخصه، مقدار زمان دلخواه خود را بدهید.
SHELL=binbash : آدرس شل پیش فرض کاربر را مشخص میکند.
SKEL=etcskel : مقدار محتویات پیش فرض داخل home directory کاربر را مشخص میکند.
CREATEMAILSPOOL=yes : برای کاربر صندوق میل درست کند یا نه.
حالا محتویات skel را ببینید.
[root@CentOS6 etc]# cd /etc/skel [root@CentOS6 skel]# ls -a . .. .bash_logout .bash_profile .bashrc .gnome2 .mozilla [root@CentOS6 skel]#
به یک روش دیگر هم میتوان مقادیر پیش فرض ایجاد کاربر را دید. استفاده از سویچ D- دستور useradd :
[root@CentOS6 etc]# useradd -D GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/bash SKEL=/etc/skel CREATE_MAIL_SPOOL=yes [root@CentOS6 etc]#
حال اطلاعات کاربران کجا ذخیره میشود ؟؟ احتمالا با فایل معروف passwd آشنا هستید. اطلاعات هویتی کاربران در این فایل به مسیر etcpasswd ذخیره میشود. اما در حالت عادی رمز کاربران در این فایل نیست. رمز hash شده کاربران در فایل etcshadow قرار دارد.
برای برگرداندن رمز ها از shadow به passwd از دستور pwunconv و برای دوباره برگرداندن رمز ها از passed به shadow از دستور pwconv استفاه کنید.
با دستور cat فایل passwd را باز کنید.
[root@CentOS6 etc]# [root@CentOS6 etc]# cat /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin gopher:x:13:30:gopher:/var/gopher:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin rtkit:x:499:496:RealtimeKit:/proc:/sbin/nologin rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin saslauth:x:498:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin haldaemon:x:68:68:HAL daemon:/:/sbin/nologin pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin ntp:x:38:38::/etc/ntp:/sbin/nologin rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin gdm:x:42:42::/var/lib/gdm:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin tcpdump:x:72:72::/:/sbin/nologin mohammad:x:500:500:mohammad:/home/mohammad:/bin/bash test:x:501:501::/home/test:/bin/bash dhcpd:x:177:177:DHCP server:/:/sbin/nologin named:x:25:25:Named:/var/named:/sbin/nologin apache:x:48:48:Apache:/var/www:/sbin/nologin [root@CentOS6 etc]#
همانطور که مشخص است، این فایل 7 ستون دارد که با : از هم جدا شدند. حال هر کدام چیست ؟؟
1- نامی که کاربر با آن log in میکند
2- کاراکتر x به جای رمز hash شذه کاربر. اگر از دستور pwunconv استفاده کنیم، رمز ها جای x مینشینند.
3- مقدار user id
4- مقدار group id
5- مقدار کامل نام کاربر یا کامنت
6- آدرس home directory کاربر
7- آدرس شل تعیین شده برای کاربر
حال فایل shadow را با دستور cat باز کنید.
[root@CentOS6 etc]# cat /etc/shadow root:$6$yUzDwtnycAln2hCt$Ut8TIzgr7PEIB.FYoqHR4PhKz7L3sG4wquDWlYRMZ42a0Gj7TI46xsv065.eCriDTFqqI.CiYOa0v.xpKamI7/:17034:0:99999:7::: bin:*:17034:0:99999:7::: daemon:*:17034:0:99999:7::: adm:*:17034:0:99999:7::: lp:*:17034:0:99999:7::: sync:*:17034:0:99999:7::: shutdown:*:17034:0:99999:7::: halt:*:17034:0:99999:7::: mail:*:17034:0:99999:7::: uucp:*:17034:0:99999:7::: operator:*:17034:0:99999:7::: games:*:17034:0:99999:7::: gopher:*:17034:0:99999:7::: ftp:*:17034:0:99999:7::: nobody:*:17034:0:99999:7::: dbus:!!:17034:0:99999:7::: avahi-autoipd:!!:17034:0:99999:7::: vcsa:!!:17034:0:99999:7::: rtkit:!!:17034:0:99999:7::: rpc:!!:17034:0:99999:7::: saslauth:!!:17034:0:99999:7::: haldaemon:!!:17034:0:99999:7::: pulse:!!:17034:0:99999:7::: postfix:!!:17034:0:99999:7::: avahi:!!:17034:0:99999:7::: ntp:!!:17034:0:99999:7::: rpcuser:!!:17034:0:99999:7::: nfsnobody:!!:17034:0:99999:7::: gdm:!!:17034:0:99999:7::: sshd:!!:17034:0:99999:7::: tcpdump:!!:17034:0:99999:7::: mohammad:$6$5a9rY41dZwqTKB/0$FwfF54aZqol3QDqu.CAWkIKnW9F/RuNC28sMd.KvT4pUklTI9Q4nVax3rYwI.o7IIRd6bIs1G9.jpUmwzwM0M.:17034:0:99999:7::: test:$6$AoyRySYi$HML82/iRkybJe1V8p9KGWiGAiU4Ha8SS7e4XeQaWmmh3BQcUY0jO3MZvblYyOXS5LqqwXHg/u2yaRp8PGNZqg0:17034:0:99999:7::: dhcpd:!!:17034:0:99999:7::: named:!!:17034:0:99999:7::: apache:!!:17034:0:99999:7::: [root@CentOS6 etc]#
این فایل 8 ستون دارد که با : از هم جدا شدند.
1- نامی که کاربر با آن log in میکند
2- رمز hash شده کاربر. اگز !! است یعنی نمیتواند log in کند
3- تاریخ آخرین تغییر رمز ( تعداد روز های گذشته از یکم ژانوبه 1970 )
4- کوتاه ترین زمان عمر رمز
5- بیشترین زمان عمر زمر
6- چند روز قبل منقضی شدن رمز به کاربر هشدار دهد
7- مقدار password inactivity که در بالاتر در فایل default توضیح دادم
8- زمان منقضی شدن اکانت کاربر
برای خواندن جزئیات بیشتر، صفحات manual این دو فایل را بخوانید. با دستور man 5 passwd و man 5 shadow.
برای تنظیم جرئیات بیشتر در مورد زمان بندی رمز ها میتوانید از فایل etclogin.defs استفاده کنید.
با دستور id مقدار uid و gid کاربری که هستید را ببینید.
[root@CentOS6 /]# whoami root [root@CentOS6 /]# id uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [root@CentOS6 /]# su - mohammad [mohammad@CentOS6 ~]$ id uid=500(mohammad) gid=500(mohammad) groups=500(mohammad) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [mohammad@CentOS6 ~]$ [mohammad@CentOS6 ~]$
بسیار خوب، حالا بریم یه چند تا مثال عملیاتی کار کنیم. به کد های زیر دقت کنید.
[root@CentOS6 ~]# useradd ali [root@CentOS6 ~]# id ali uid=502(ali) gid=502(ali) groups=502(ali) [root@CentOS6 ~]# ls -l /home total 12 drwx------. 4 ali ali 4096 Aug 21 21:53 ali drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad drwx------. 4 test test 4096 Aug 29 2015 test [root@CentOS6 ~]# useradd reza [root@CentOS6 ~]# id reza uid=503(reza) gid=503(reza) groups=503(reza) [root@CentOS6 ~]# ls -l /home total 16 drwx------. 4 ali ali 4096 Aug 21 21:53 ali drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad drwx------. 4 reza reza 4096 Aug 21 21:53 reza drwx------. 4 test test 4096 Aug 29 2015 test [root@CentOS6 ~]# useradd bob -c "sponge bob" [root@CentOS6 ~]# ls -l /home total 20 drwx------. 4 ali ali 4096 Aug 21 21:53 ali drwx------. 4 bob bob 4096 Aug 21 22:10 bob drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad drwx------. 4 reza reza 4096 Aug 21 21:53 reza drwx------. 4 test test 4096 Aug 29 2015 test [root@CentOS6 ~]# id bob uid=504(bob) gid=504(bob) groups=504(bob) [root@CentOS6 ~]# tail -3 /etc/passwd ali:x:502:502::/home/ali:/bin/bash reza:x:503:503::/home/reza:/bin/bash bob:x:504:504:sponge bob:/home/bob:/bin/bash [root@CentOS6 ~]# userdel -r bob [root@CentOS6 ~]# ls -l /home total 16 drwx------. 4 ali ali 4096 Aug 21 21:53 ali drwx------. 28 mohammad mohammad 4096 Aug 21 21:49 mohammad drwx------. 4 reza reza 4096 Aug 21 21:53 reza drwx------. 4 test test 4096 Aug 29 2015 test [root@CentOS6 ~]# tail -3 /etc/shadow apache:!!:17034:0:99999:7::: ali:!!:17034:0:99999:7::: reza:!!:17034:0:99999:7::: [root@CentOS6 ~]# passwd ali Changing password for user ali. New password: BAD PASSWORD: it is WAY too short BAD PASSWORD: is too simple Retype new password: passwd: all authentication tokens updated successfully. [root@CentOS6 ~]# tail -3 /etc/shadow apache:!!:17034:0:99999:7::: ali:$6$q.RMBAcT$oSMQGn.GJB7s2vdEtEFGMyfxqph3DVxK9yUkVSRkMiYzdyRhoOwPK8JYIVauW8uKip5CFjxl76HWfLrSRq1jW/:17034:0:99999:7::: reza:!!:17034:0:99999:7::: [root@CentOS6 ~]# usermod -L ali [root@CentOS6 ~]# tail -3 /etc/shadow apache:!!:17034:0:99999:7::: ali:!$6$q.RMBAcT$oSMQGn.GJB7s2vdEtEFGMyfxqph3DVxK9yUkVSRkMiYzdyRhoOwPK8JYIVauW8uKip5CFjxl76HWfLrSRq1jW/:17034:0:99999:7::: reza:!!:17034:0:99999:7::: [root@CentOS6 ~]# usermod -U ali [root@CentOS6 ~]# tail -3 /etc/shadow apache:!!:17034:0:99999:7::: ali:$6$q.RMBAcT$oSMQGn.GJB7s2vdEtEFGMyfxqph3DVxK9yUkVSRkMiYzdyRhoOwPK8JYIVauW8uKip5CFjxl76HWfLrSRq1jW/:17034:0:99999:7::: reza:!!:17034:0:99999:7::: [root@CentOS6 ~]# date --date "17034 days ago" Thu Jan 1 20:49:23 IRST 1970 [root@CentOS6 ~]#
همشو میگم !!! نگران نباشید !!!
با دستور useradd ali یک کاربر با نام ali درست کردم. اگر دستور id ali را بزنم ، مقدار uid و gid را برای او نشان میدهد. ( پس اون مقدار پیش فرض 100 چی بود ؟؟ برید سرچ کنید، بعدا میگم چرا اینجوریه. یکی کامنت بزاره چرا اینجوریه. ) اگر home/ را باز کنم، میبینم که برای ali پوشه هم درست کرده. ممکنه درست نکنه، نسخه من درست میکنه، اگر برای شما درست نکرد ، دستور useradd رو با m- بزنید. وقتی پوشه درست نمیکنه، تا اون کاربره log in نکنه، پوشه درست نمیشه. دستور useradd سویچ ها مختلف و مهمی داره. مثلا سویچ c- برای مشخص کردن نام کامل کاربر یا کامنت استفاده میشه ( بالاتر تو passwd گفتم ) . با دستور userdel هم کاربر را پاک کنید.
اگر با سویچ r- استفاده کنید home directory و mail box او را هم پاک میکند. حال فایل shadow رو نگاه کنید. اون !! چی میگه ؟؟ چون واسه کاربر پسورد نذاشتیم. کلا اول ستون پسورد ! باشه ینی کاربر قفله ( ینی نمیتونه log in کنه) حالا با دستور passwd برای ali پسورد میذارم. اگه دوباره فایل shadow رو ببینید، دیگه ali قفل نیست. ( اول ستون رمز ! نیست ) . حالا اگه بخوایم یه کاربر را قفل کنیم. ( مثلا تنبیهش کنیم، نتونه وارد بشه ) از دستور usermod با سویچ L- استفاده میکنیم. بعدش برید shadow رو ببینید، یه ! اول رمزش اضافه شده ( ینی رفت تو باقالیا !!! قفل شد !!! ) حالا ali توبه کرده میخوایم از قفلی درش یاریم، از دستور usermod با سویچ U- استفاده میکنیم. علامت ! از اول رمزش برداشته شد.
اون 17034 هم تعداد روز گذشته از آخرین تغییر پسورد رو میگه نسبت به اول ژانویه 1970... اگه باور نمیکنید، خروجی دستور date رو ببینید.ینی آخرین باری که پسورد عوض شد از اول ژانویه 1970 تعداد 17034 روز گرشته بود.کاربر بدون رمز هم نمیتونه log in کنه، یادتون باشه اینو.
همانطور که گفتم، این جلسه در مورد گروه ها صحبت میکنیم. اصلی ترین فایل اطلاعات گروه ها، فایل group در زیر شاخه etc است. آن را باز کنید.
[root@CentOS6 ~]# cat /etc/group root:x:0: bin:x:1:bin,daemon daemon:x:2:bin,daemon sys:x:3:bin,adm adm:x:4:adm,daemon tty:x:5: disk:x:6: lp:x:7:daemon mem:x:8: kmem:x:9: wheel:x:10: mail:x:12:mail,postfix uucp:x:14: man:x:15: games:x:20: gopher:x:30: video:x:39: dip:x:40: ftp:x:50: lock:x:54: audio:x:63: nobody:x:99: users:x:100: dbus:x:81: utmp:x:22: utempter:x:35: ctapiusers:x:499: desktop_admin_r:x:498: desktop_user_r:x:497: avahi-autoipd:x:170: floppy:x:19: vcsa:x:69: rtkit:x:496: rpc:x:32: cdrom:x:11: tape:x:33: dialout:x:18: saslauth:x:76: haldaemon:x:68:haldaemon pulse:x:495: pulse-access:x:494: fuse:x:493: postdrop:x:90: postfix:x:89: avahi:x:70: ntp:x:38: rpcuser:x:29: nfsnobody:x:65534: gdm:x:42: stapusr:x:156: stapsys:x:157: stapdev:x:158: sshd:x:74: tcpdump:x:72: slocate:x:21: mohammad:x:500: test:x:501: dhcpd:x:177: named:x:25: apache:x:48: ali:x:502: reza:x:503: [root@CentOS6 ~]#
این فایل 4 ستون دارد که مانند فایل passwd با : جدا شده اند.
1- نام گروه
2- رمز گروه که یه جای آن x آمده
3- مقدار group id
4- لیست اعضا که با ، از هم جدا شده اند.
مثل فایل passwd که یک فایل shadow هم دارد، فایل group هم یک shadow دارد ولی اسم آن gshadow است. آن را در etc پیدا میکنید
[root@CentOS6 ~]# cat /etc/gshadow root::: bin:::bin,daemon daemon:::bin,daemon sys:::bin,adm adm:::adm,daemon tty::: disk::: lp:::daemon mem::: kmem::: wheel::: mail:::mail,postfix uucp::: man::: games::: gopher::: video::: dip::: ftp::: lock::: audio::: nobody::: users::: dbus:!:: utmp:!:: utempter:!:: ctapiusers:!:: desktop_admin_r:!:: desktop_user_r:!:: avahi-autoipd:!:: floppy:!:: vcsa:!:: rtkit:!:: rpc:!:: cdrom:!:: tape:!:: dialout:!:: saslauth:!:: haldaemon:!::haldaemon pulse:!:: pulse-access:!:: fuse:!:: postdrop:!:: postfix:!:: avahi:!:: ntp:!:: rpcuser:!:: nfsnobody:!:: gdm:!:: stapusr:!:: stapsys:!:: stapdev:!:: sshd:!:: tcpdump:!:: slocate:!:: mohammad:!!:: test:!:: dhcpd:!:: named:!:: apache:!:: ali:!:: reza:!:: [root@CentOS6 ~]#
این فابل هم 4 ستون دارد که با : از هم جدا شدند.
1- نام گروه
2- رمز hash شده گروه
3- اسامی ادمین های گروه که با ، حدا میشوند
4- اسامی اعضای گروه
فایل manula این دو تا فبلی که ذکر شد رو هم با دستور man 5 group و man 5 gshadow ببینید.
یادتونه جلسه قبل برای کاربران group id پیش فرض مشخص کردیم ولی وقتی کاربر ساختیم از اون پیش فرض تبعیت نکرد ؟؟ رفتید سرچ کنید ؟؟ نرفتید دیگه !!! هیچ کی نگفت چرا اینجوری شد... خودم میگم حالا... گوش کنید پس.
دیدید وقتی یه کاربر اضافه کردیم، عضو گروهی به اسم خودش شد. به این گروه هایی که اینجوری درست میشن میگن private groups. پس private group در حالت عادی فعال است و باعث میشود هر کاربر جدیدی عضو گروه خودش شود و از مقدار پیش فرض تبعیت نکند. اگر غیر فعالش کنیم از مقدار پیش فرض تبعیت میکند.
یه کد های زیر دقت کنید.
[root@CentOS6 ~]# useradd -m jim [root@CentOS6 ~]# id jim uid=502(jim) gid=502(jim) groups=502(jim) [root@CentOS6 ~]# grep USERGROUP /etc/login.defs USERGROUPS_ENAB yes [root@CentOS6 ~]# useradd -g users -m jack [root@CentOS6 ~]# id jack uid=503(jack) gid=100(users) groups=100(users) [root@CentOS6 ~]#
با دستور useradd و سویچ m- یک کاربر درست کردم. اگر مقادیر id را برای اون چک کنم، میبینم که مقدار پیش فرض را نگرفته. حالت private groups در فایل login.defs تعریف میشود. در حالت عادی هم فعال است که مشاهده میکنید. حال اگر این بار یک کاربر دیگر اضافه کنم ولی با سویچ g- و کلمه user بعدش id را چک کنم میبینم که از مقدار پیش فرض تبعیت کرده. در این حالت با سویچ g- به معنی primary group این حالت فعال بودن private groups را موقتا نادیده گرفتیم.
دو مفهوم جدید اینجا بوجود می آید. g- برای primary groups و G- برای secondary groups. هر کدام به چه معناست ؟؟
یکم توضیحش ظریفه اینجا. دقت کنید. امیدوارم راحت متوجه بشید. وقتی یک کاربر یک فایل را باز میکنه یا برنامه ای را اجرا میکنه یا هر چی دیگه، به دسترسی های primary group اون بستگی داره. وقتی یک کاربر فایل درست میکنه، اونو با دسترسی و مالکیت primary group درست میکنه. هر کس دیگه ای هم که توی اون primary group باشه اگه دسترسی تعریف شده باشه، میتونه اون فایل رو ببینه یا بخونه یا اجرا کنه. مثلا یک primary group دارم به اسم admins... هر کی ادمین بخش های مختلف هستش رو عضو این گروه کردم. هر کس در چارچوب این گروه اجازه دسترسی به منابع مختلف رو توی این گروه داره و هر کسی تو این گروه فایلی درست کنه یا مسیری بسازه مالکیت اون مسیر یا فایل به primary group برمیگرده، یعنی مثلا این فابل متعلق به گروه ادمین هاست، چون یکی که عضو این گروه بوده اینو درست کرده. ولی حالا secondary group چیه؟ حالا برای هر کاربر یک یا چند secondary group هم میشه تعریف کرد.
[root@CentOS6 ~]# usermod -G mali,hr jack [root@CentOS6 ~]# id jack uid=503(jack) gid=100(users) groups=100(users),12(mali),504(hr) [root@CentOS6 ~]#
برای کاربر دو گروه مالی و منابع انسانی رو به عنوان secondary groups مشخص کردم. در خروجی دستور id میبینیم که گروه user با شماره 100 به عنوان primary group برای jack تعریف شده، 2 گروه mali و hr هم به عنوان secondary group، علاوه بر خود گروه users. حالا jack دسترسی ها و امکانات گروه hr و mali را هم دارد و میتواند با سطح دسترسی آنها کاری انجام دهد، میتواند به فایل های در مالکیت این گروه ها دسترسی داشته باشد، ولی اگر فایلی درست کند با دسترسی primary group درست میشود. پس هر کاربر میتواند در یک لحظه فقط و فقط یک primary group ولی چندین secondary group داشته باشد. اصطلاحا secondary group ها باعث ایجاد addition access برای کاربر میشوند.
به دستورات زیر دقت کنید.
[root@CentOS6 ~]# useradd -N -m sally [root@CentOS6 ~]# id sally uid=504(sally) gid=100(users) groups=100(users) [root@CentOS6 ~]#
هنگام ایجاد کاربر با سویچ N- به معنی no user group میتوان از تنظیمات پیش فرض استفاده کرد.
به دستورات زیر دقت کنید.
[root@CentOS6 ~]# grep hr /etc/group hr:x:504:jack [root@CentOS6 ~]# grep mali /etc/group mali:x:503:jack [root@CentOS6 ~]# grep mali /etc/gshadow mali:!::jack [root@CentOS6 ~]# id sally uid=504(sally) gid=100(users) groups=100(users) [root@CentOS6 ~]# gpasswd -M sally mali [root@CentOS6 ~]# id sally uid=504(sally) gid=100(users) groups=100(users),503(mali) [root@CentOS6 ~]# grep mali /etc/group mali:x:503:sally [root@CentOS6 ~]# usermod -G mali jack [root@CentOS6 ~]# grep mali /etc/group mali:x:503:sally,jack [root@CentOS6 ~]# gpasswd -M sally mali [root@CentOS6 ~]# grep mali /etc/group mali:x:503:sally [root@CentOS6 ~]# usermod -G mali jack [root@CentOS6 ~]# grep mali /etc/group mali:x:503:sally,jack [root@CentOS6 ~]#
حالا فایل های group و gshadow را نگاه کنید. برای گروه mali عضو جدیدی تعریف شده است ولی رمزی برای گروه تعذیف نشده. با دستور gpasswd هم میتوان برای کاربر secondary group تعریف کرد ولی با دستور usermod فرق دارد. تفاوت در کد بالا واضح است. انگار دستور gpasswd با سویچ M- به معنای member list لیست اعضای گروه ها overwrite میکند. با دقت استفاده کنید.
به کد های زیر دقت کنید. اگر میخواهیم که خود کاربر بتواند وارد گروهی شود، میتوانیم برای گروه رمز بگذاریم. البته این عضویت در گروه موقتی است و با خروج کاربر، به گروه قبلی خود بازمیگردد. برای عضویت دائمی میدانید چه باید بکنبم. یه مثال ساده پایین زدم.
[root@CentOS6 ~]# groupadd security [root@CentOS6 ~]# gpasswd security Changing the password for group security New Password: Re-enter new password: [root@CentOS6 ~]# grep security /etc/gshadow security:$6$ydWgczUOpFI0t/iB$Xzvy/j4vVYerZ53JBSH.UP3aOocMrQHdO7cCzhLfZarWVt80/MlA08z7..q17dbRptQMrOCepDxo4/saLn2Nr1:: [root@CentOS6 ~]# useradd -N testuser [root@CentOS6 ~]# id testuser uid=505(testuser) gid=100(users) groups=100(users) [root@CentOS6 ~]# passwd testuser Changing password for user testuser. New password: BAD PASSWORD: it is WAY too short BAD PASSWORD: is too simple Retype new password: passwd: all authentication tokens updated successfully. [root@CentOS6 ~]# su - testuser [testuser@CentOS6 ~]$ [testuser@CentOS6 ~]$ whoami testuser [testuser@CentOS6 ~]$ pwd /home/testuser [testuser@CentOS6 ~]$ [testuser@CentOS6 ~]$ [testuser@CentOS6 ~]$ id uid=505(testuser) gid=100(users) groups=100(users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [testuser@CentOS6 ~]$ [testuser@CentOS6 ~]$ newgrp security Password: [testuser@CentOS6 ~]$ id uid=505(testuser) gid=505(security) groups=100(users),505(security) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [testuser@CentOS6 ~]$ [testuser@CentOS6 ~]$ exit exit [testuser@CentOS6 ~]$ id uid=505(testuser) gid=100(users) groups=100(users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 [testuser@CentOS6 ~]$ [testuser@CentOS6 ~]$
در این جلسه به مبحث مدیریت کاربران Active Directory از طریق سیستم عامل لینوکسی خود میپردازیم. یکی از package هایی که میتوان برای این کار استفاده کرد pbis است. تا اونجایی که من میدونم در repository های پیش فرض centos وجود ندارد و باید یا repository را بروز رسانی کنیم یا فایل نصبی package را دانلود کرده و دستی نصبش کنیم. برای بروز رسانی repository خود از دستور زیر در centos استفاده کنید.
[root@CentOS6 ~]# wget -O /etc/yum.repos.d/pbiso.repo http://repo.pbis.beyondtrust.com/yum/pbiso.repo
چند ثانیه بیشتر بروز رسانی طول نمی کشد. پس از آن میتوانید pbis را نصب کنید.
[root@CentOS6 ~]# yum clean all [root@CentOS6 ~]# yum install pbis-open
من یک windows server 2012 R2 دارم که روش Active Directory و DNS نصب شده. 2 نکته مهم این است که هر دو سیستم عامل centos و windows server باید از لحاظ زمانی با هم sync باشند. با vm tools این کار را میتوانید انجام دهید و دوم اینکه DNS سرور برای centos ، همون window server قرار داده شده. آی پی windows server رو دادم بهش به عنوان nameserver.پس از اینکه مطمئن شدید 2 تا سیستمتون به هم ارتباط دارن ( با یه پینگ ساده ) دستورات زیر رو توی ترمینال لینوکس وارد کنید. ( فایر وال ویندوز سرور رو خاموش کنید تا پینگ بده، آموزش ایجاد ارتباط بین لینوکس و ویندوز توی vmware تو نت ریخته )
[root@CentOS6 ~]# domainjoin-cli join winserver2012.ir Administrator Joining to AD Domain: winserver2012.ir With Computer DNS Name: CentOS6.winserver2012.ir Administrator@WINSERVER2012.IR's password: Warning: System restart required Your system has been configured to authenticate to Active Directory for the first time. It is recommended that you restart your system to ensure that all applications recognize the new settings. SUCCESS [root@CentOS6 ~]# reboot
خط اول که یک دستور اتصال به دامینه، اسم دامین و اکانت ادمین رو باید وارد کنید. بعدش باید سیستم رو reboot کنید.
حالا اگر دستور زیر را در ترمینال وارد کنید، تمام کاربران سیستم لینوکسی و Domain را میبینید.
[root@centos6 ~]# getent passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt mail:x:8:12:mail:/var/spool/mail:/sbin/nologin uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin operator:x:11:0:operator:/root:/sbin/nologin games:x:12:100:games:/usr/games:/sbin/nologin gopher:x:13:30:gopher:/var/gopher:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin nobody:x:99:99:Nobody:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/sbin/nologin vcsa:x:69:69:virtual console memory owner:/dev:/sbin/nologin rtkit:x:499:496:RealtimeKit:/proc:/sbin/nologin rpc:x:32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin saslauth:x:498:76:"Saslauthd user":/var/empty/saslauth:/sbin/nologin haldaemon:x:68:68:HAL daemon:/:/sbin/nologin pulse:x:497:495:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin postfix:x:89:89::/var/spool/postfix:/sbin/nologin avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin ntp:x:38:38::/etc/ntp:/sbin/nologin rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin gdm:x:42:42::/var/lib/gdm:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin tcpdump:x:72:72::/:/sbin/nologin mohammad:x:500:500:mohammad:/home/mohammad:/bin/bash test:x:501:501::/home/test:/bin/bash dhcpd:x:177:177:DHCP server:/:/sbin/nologin named:x:25:25:Named:/var/named:/sbin/nologin apache:x:48:48:Apache:/var/www:/sbin/nologin jim:x:502:502::/home/jim:/bin/bash jack:x:503:100::/home/jack:/bin/bash sally:x:504:100::/home/sally:/bin/bash testuser:x:505:100::/home/testuser:/bin/bash WINSERVER2012\administrator:PBIS:1237844468:1237844481::/home/local/WINSERVER2012/administrator:/bin/sh WINSERVER2012\guest:PBIS:1237844469:1237844482::/home/local/WINSERVER2012/guest:/bin/sh WINSERVER2012\krbtgt:PBIS:1237844470:1237844481::/home/local/WINSERVER2012/krbtgt:/bin/sh WINSERVER2012\user1:PBIS:1237845088:1237844481:user1:/home/local/WINSERVER2012/user1:/bin/sh WINSERVER2012\user2:PBIS:1237845089:1237844481:user2:/home/local/WINSERVER2012/user2:/bin/sh [root@centos6 ~]#
اولاش که همه کاربرای سیستم لینوکسی خودمه، چند خط آخر کاربرانیه که نوی Active Directory درست کردم. فرمتش واضحه ... ولی این اطلاعات از کجا میاد ؟؟ اگر کلمه passwd رو از فایل زیر در مسیر etc جستجو کنیم، خروجی زیر را میبینیم:
[root@centos6 ~]# grep passwd /etc/nsswitch.conf #passwd: db files nisplus nis passwd: files lsass [root@centos6 ~]#
فایل nsswitch مشخص میکند که چه سرویسی و از کجا برای مشخص کردن مواردی مثل host name و password و group استفاده بشه. این فایل خیلی توضیخ داره. میتونید فایل رو باز کنید تا همشو ببینید. پارامتر های زیادی داره. حالا همین یه تیکه ای که ما کشیدیم بیرون. خط اول که کامنته مشخص میکنه که خط پایینیش که دستوره، از چه اجرایی تشکیل شده. مثلا برای مشخص کردن پسورد ها ، ائل نوشته files، یعنی ابتدا فایل های local سیستم رو بگرد ( یعنی برو توی فایل etcpasswd و etcpasswd بگرد دنبال چیزی که گفتم. ) بعدش گفته lsass. اصل کار ما اینه. این میره از توی Active Directory اطلاعات کاربرا رو میکشه بیرون. حروفش از local security authority sub systems میاد. این همون پروسه ایه که باهاش به Active Directory وصل شدیم. اگر شما دارید از centos 7 به بالا استفاده میکنید ( که من استفاده نمیکنم ) بعد از files یه sss هم میبینید به معنی system security services هستش که توی این نسخه های جدید centos استفاده شده و توی پیش فرض های سیستم عامله.
هر خط فایل nsswitch مشخص میکند که برای جمع آوری چه اطلاعاتی ، از چه منابعی استفاده کند. این فایل درمورد موارد زیر میتواند به جستجوی اطلاعات بپردازد:
automount Automount (/etc/auto.master and /etc/auto.misc) bootparams Diskless and other booting options (See the bootparam man page.) ethers MAC address group Groups of users (/etc/group ) hosts System information (/etc/hosts ) netgroup Netgroup information (/etc/netgroup ) networks Network information (/etc/networks ) passwd User information (/etc/passwd ) protocols Protocol information (/etc/protocols ) publickey Used for NFS running in secure mode rpc RPC names and numbers (/etc/rpc ) services Services information (/etc/services ) shadow Shadow password information (/etc/shadow )
بعد از مشخص کردن نوع اطلاعات، مشخص میکند که از چه طریقی آنها را پیدا کند.
files = > Searches local files such as /etc/passwd and /etc/hosts nis => Searches the NIS database; yp is an alias for nis dns => Queries the DNS (hosts queries only) compat ± => syntax in passwd, group, and shadow files
پس به ترتیبی که مشخص کردیم، میرود از منابعی که مشخص کردیم، پرس و جو میکند. دیدیم بالاتر که اول نوشته بود files و سپس lsass. اول برو سراغ files بعدش lsass.
حالا بیاید بریم سر یه مبحث دیگه. مثلا کاربری که در Active Directory تعریف شده بتونه یه home directory توی سیستم لینوکسی ما داشته باشه.
به دستورات زیر دقت کنید.
[root@centos6 ~]# mkdir /home/user1 [root@centos6 ~]# chown winserver2012\\user1 /home/user1/ [root@centos6 ~]# ls -ld /home/user1/ drwxr-xr-x. 2 WINSERVER2012\user1 root 4096 Aug 23 21:18 /home/user1/ [root@centos6 ~]# su - winserver2012\\user1 -sh-4.1$ -sh-4.1$ -sh-4.1$ id uid=1237845088(WINSERVER2012\user1) gid=1237844481(WINSERVER2012\domain^users) groups=1237844481(WINSERVER2012\domain^users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 -sh-4.1$
یه پوشه پیش فرض واسه کاربران درست کرده بود که توی خروجی دستور getent دیدید. اگر اشتباه نکنم اون پوشه تا زمانی که کاربر log in نکنه ایجاد نمیشه. حالا علاوه بر اون یه پوشه اگر بخوایم درست کنید به ترتیب بالا انجامش میدیم. پس از درست کردن پوشه باید ماکیت اونو با دستور chown به معنی change ownership تغییر بدیم. به ساختار دستور دقت کنید چجوری نوشتم. بعدش با دستور su کاریری که هستم رو تغییر دادم. چون روت بودم ازم رمز نخواست. حالا با نام کاریری user1 که در AD تعریف شده، وارد سیستم شدم.
-sh-4.1$ -sh-4.1$ -sh-4.1$ whoami WINSERVER2012\user1 -sh-4.1$ -sh-4.1$ pwd /home/local/WINSERVER2012/user1 -sh-4.1$ -sh-4.1$ -sh-4.1$ echo $PATH /usr/lib/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin -sh-4.1$ -sh-4.1$
در این جلسه به یکی از مباحث مهم در شبکه یعنی ldap میپردازیم. اول از همه باید بفهمیم که چرا به ldap نیاز داریم و اصلا ldap چیست؟؟ ابتدا مقداری مقدمه میگم و بعدش میریم سراغ یک سناریوی عملی، نمیدونم حالا میشه تو یه قسمت جمعش کرد یا نه چیزی رو که میخوام بگم.
مفهوم Directory Service به چه معناست ؟؟
طبق تعریف directory service یک بانک اطلاعاتی است که قدرت آن در جستجو و خواندن اطلاعات با سرعت بالاست. نه اینکه در نوشتن ضعیف باشه، ولی در بعضی شرایط ما نیاز داریم که اطلاعاتی را با سرعت بالا از بانک اطلاعاتی بخوانیم. در چنین بانک های اطلاعاتی یک رکورد یا یک entry یک بار نوشته میشود ولی قرار است هزاران هزار بار خوانده شود، پس باید سرعت خواندن اطلاعات بالا یاشد. ساده ترین directory service یک دفترچه تلفن است. وقتی مثلا نام ali را ذخیره میکنیم، میرویم در قسمت حرف a نام او را ذخیره میکنیم. بعدا هم وقتی دنبال او بگردیم، میرویم فقط قسمت a را جستجو میکنیم، نه کل دفترچه. در اینجا ali یک object یا entry است. این object میتواند attribute هم داشته باشد مثل ایمیل و آدرس و ... . پس Directory Service یک سیستم درختی است. در حقیقت Directory Service یک سیستم جستجو گر است که میتوان نتیجه یک جستجو را trace کرد که از کجا آمده. یه شکل زیر دقت کنید.
فرض کنید یک پایگاه داده داریم که شامل تمام کمپانی های دنیا است. دنیال یک شخص خاص در این پایگاه داده میگردیم. بصورت درختی به جستجو میپردازیم. اول میپرسی که در کدام کشور است ؟ مثلا آمریکا، خوب بقیه کشور ها رو میزاریم کنار. در کدام ایالت است؟ کالیفورنیا، نام کمپانی او چیست؟ مثلا acme ، در کدام بخش کار میکند ؟ فروش، نامش چیست ؟ barbara jenson . این یک جستجوی درختی بود. در چنین سیستمی فقط قسمتی از پایگاه داده که لازم است رو جستجو میکنیم نه همشو. در ضمن سرعت جستجو هم باید بالا باشد. این یک سیستم میتنی بر Directory Service است. حال برای اینکه بتوان اطلاعات را در Directory Service ذخیره کرد و به این صورت که گفتیم قابل جستجو باشند، نیاز به یک استاندارد خاص دخیره سازی اطلاعات است. این استاندارد x500 نام دارد. به شکل نگاه کنید ( نخندید!!! با paint کشیدم !!! )
اطلاعات با استاندارد x500 بصورت زیر درختی و زیر شاخه ای ذخیره میشود. حال برای دسترسی به این اطلاعات باید از یه پروتکلی استفاده کنیم. این پروتکل در قدیم dap نام داشت که نسخه بهبود یافته آن شد ldap. پروتکل dap سنگین بود و منابع زیادی مصرف میکرد ولی ldap که از اسمش هم مشخصه Lightweight Directory Access Protocol همون dap سبک شده است. پروتکل ldap محصول IBM و Microsoft است. به سروری که اطلاعات رو با استاندارد x500 ذخیره میکنه میگیم ldap server . پس ldap یک پروتکل دسترسی است. خود ldap server به تنهایی پایگاه داده ندارد. در آن یک پایگاه داده میسازیم. اگر ldap server بخواهیم داشته باشیم، در ویندوز، Active Directory و در لینوکس هم OpenLDAP نصب میکنیم. تمام این ها از استاندارد x500 استفاده میکنند. ماکروسافت بانک اطلاعاتی خودشو داره توی AD ولی نام پایگاه داده لینوکس BDB است. استفاده از ldap server باید توجیه پذیر باشد. مثلا بانک ها از چنین سرویسی استفاده نمیکنند و به جای ldap server از oracle استفاده میکنند. البته ممکنه چیزای دیگه ای مثل آرشیوشون یا اطلاعات سازمانی رو روی ldap server نگه دارن ولی اطلاعات مالی و تراکنش مالی که هر روز انجام میشه رو نه ( چرا ؟؟؟ اینو دیگه خودم نمیگم، شما بگید !!! )
پس کلا اطلاعاتی رو روی ldap server میبریم که قراره یک بار نوشته بشه ولی هزاران بار توسط کاربران یا برنامه ها خونده بشه و استفاده بشه. کلا سرعت read بالا میخوایم نه write خیلی بالا.
بسیار خوب. فک میکنم واسه مقدمه کافیه چون بحث خیلی گستردس نمیشه جمعش کرد. بریم سراغ نصب ldap server روی 5.8 centos
فقط یادتون باشه object هایی که درست میکنیم لینوکسی نیستن، ینی اگه یه کاربر ساختیم نمیتونه تو سیستم log in کنه. اون بحثش یه چیز دیگس. اون میره توی بحثای مربوط به samba.
Open LDAP
در ترمینال خود دستور زیر را برای نصب package های لازم وارد کنید.
[root@localhost ~]# yum install openldap openldap-clients openldap-servers
بعد از اینکه نصب شد میتونم چک کنم
[root@localhost ~]# rpm -qa | grep openldap openldap-clients-2.3.43-29.el5_11 openldap-2.3.43-29.el5_11 openldap-servers-2.3.43-29.el5_11 [root@localhost ~]#
دیدید که 3 تا package نیاز دارم. استاندارد x500 با نصب openldap server نصب شد. openldap client که ابزارهای وصل شذن به این پایگاه داده و مدیریتشه. openldap هم که لازمه جفتشه.
حالا این openldap server یک فایل کانفیگ داره. بر خلاف انتظار، این فایلی که پایین نوشتم نیست !!! این کامفیگ فایل کاربره نه سرورو تنظیمات کاربر توی این وارد میشه
/etc/openldap/ldap.conf
تنظیمات مربوط به سرور توی slapd.conf قرار داره.
[root@localhost ~]# cd /etc/openldap/ [root@localhost openldap]# ls cacerts DB_CONFIG.example ldap.conf schema slapd.conf [root@localhost openldap]#
فایل slapd.conf رو با یه ادیتور باز کنید. توی خط 86 و 87 و 93 اطلاعات رو مطابق شکل زیر تغییر بدبد. این شکلی بشه.
حالا اینا چی هست ؟؟ اون فایل هایی که بالای سند include شدن schema هستن برای ldap server ... این schema ها ساختاری برای ایجاد همون پایگاه داده با استامدارد x500 هستن. اینا schema های پایه هستن. مثلا اگه میخوام samba رو هم با ldap ی که دارم integrate کنم ، بعد از اینکه samba رو نصب کردم، برم فایل های schema ی samba رو پیدا کنم، برم توی پوشه schema های ldap کپیش کنم و بعدش بیام توی این فایل include کنمش. هر برنامه ای که بخواد با ldap سرور integrate بشه باید object های برنامه واسه ldap تعریف شده باشه، object ها هم توی schema تعریف میشه. توی عکسی که از فایل slapd گذاشتم میبینید که نوشته پایگاه داده BDB باشه، suffix میگه این قراره کانفیگ فایل چه دامینی باشه؟ حالا مثلا سازمانمون tosinso.com باشه. این فرمت رو باید رعایت کنید. dc یعنی domain component . خط بعد میگه حالا کاربر ارشد این ldap server کیه ؟ کاربر ارشد اینجا manager نام داره. باز اون فرمت رو رعایت کنید. مدیر توی کدوم دامین قرار داره؟ cn یعنی common name . بعدشم دامین مدیر ارشد رو مشخص کردیم. خط بعدش رمز کاربر ارشد رو میخواد. میتونیم رمز رو بصورت clear text اینجا بنویسیم، میتونیم هش شده رمز رو خط بعد بنویسیم. فایل رو ذخیره کنید و سرویس رو روشن کنید. بعدش پورت هایی که listen میشن رو چک کنید. ldap روی پورت 389 در حالت پیش فرض کار میکنه.
[root@localhost openldap]# /etc/init.d/ldap start Starting slapd: [ OK ] [root@localhost openldap]# netstat -antp | grep 389 tcp 0 0 0.0.0.0:389 0.0.0.0:* LISTEN 8252/slapd tcp 0 0 :::389 :::* LISTEN 8252/slapd [root@localhost openldap]#
سرویس ldap راه افتاد ولی هنوز بانک اطلاعاتیمون خالیه. باید توش اطلاعات وارد کنیم. با دستور ldapadd ما میتونیم object اضافه کنیم. این object میتونه سازمان باشه، میتونه بخش سازمانی باشه، میتونه کارمند باشه. دستور زیر رو وارد کنید تا همه پایگاه داده رو نشون بده.
[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)" # extended LDIF # # LDAPv3 # base <dc=itpro,dc=com> with scope subtree # filter: (objectclass=*) # requesting: ALL # # search result search: 2 result: 32 No such object # numResponses: 1 [root@localhost openldap]#
نوشتن objectclass برابر * یعنی همه رو نشون بده. محدوده جستجو رو گذاشتم از کل دامین ، با سویچ b- و دادن نام دامین. x-هم یعنی از سیستم simple authentication استفاده کن. حالا این چیزی برنگردوند چون پایگاه داده خالیه. حالا ما میخوایم ریشه سازمان رو تعریف کنیم، دپارتمان ها رو اضافه کنیم، بعدش کارمند ها رو اضافه کنیم. اطلاعاتی که میخوام وارد کنم رو توی یک فایل میریزم که باید با فرمت ldif نوشته شده باشن. ldap data interchange format . دستور ldapadd خیلی سویچ داره. یه کوچولوشو میگیم اینجا. W- یعنی تقاضای رمز کن. با f- هم فایل ldif رو نشونش میدم. x- هم یعنی simple authentication بکن. D- یعنی با چه یوزری از کدوم دامین میخوای وارد بشی. یک فایل به اسم build-root-ou.ldif درست کنید. اطلاعات زیر رو واردش کنید.
dn: dc=itpro,dc=com objectclass: dcObject objectclass: organization o: itpro dc: itpro
یه dn درست کردم به همراه صفاتش . dn ریشه سازمان رو تو دل خودش داره. dn یعنی distinguished name . ریشه سازمان رو ساختم. هر object که اضافه میکینم باید dn یکتا داشته باشه. خط پایین dc:itpro یک صفته. خط آخر هم o یک صفنه یعنی organization. برای هر object حداقل یک objectclass باشد تعریف بشه. معمولا برای تعریف سازمان، 2 تا objectclass که نوشتم رو استفاده میکنن. اینا صفات رو تعریف میکنن. یعنی من اگه خواستم صفات تعریف کنم واسه سازمانم، از صفات تعریف شد توی objectclass میتونم استفاده کنم نه هر صفنی.
حالا این فایل رو باید به پایگاه داده اضافه کنم.
[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -W -x -f build_root_ou.ldif
اگه همه چی رو درست وارد کرده باشید، entry به درستی در پتیگاه داده وارد میشه.
برای تست کردن اینکه فایل slap.d رو درست کانفیگ کردید یا نه دستور زیر رو بزنید
[root@localhost openldap]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts # extended LDIF # # LDAPv3 # base <> with scope baseObject # filter: (objectclass=*) # requesting: namingContexts # # dn: namingContexts: dc=itpro,dc=com # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 [root@localhost openldap]#
حالا اگه دوباره از پایگاه داده query بگیریم
[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)" # extended LDIF # # LDAPv3 # base <dc=itpro,dc=com> with scope subtree # filter: (objectclass=*) # requesting: ALL # # itpro.com dn: dc=itpro,dc=com objectClass: dcObject objectClass: organization o: itpro dc: itpro # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1 [root@localhost openldap]#
حالا میخوام مدیر سازمان رو اضافه کنم. یک فایل به اسم add-manager.ldif درست میکنم
dn: cn=Manager,dc=itpro,dc=com objectclass: organizationalRole cn: Manager
اینطوری هم اضافش میکنم به پایگاه داده
[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -h localhost -W -x -f build_manager.ldif Enter LDAP Password: adding new entry "cn=Manager,dc=itpro,dc=com" [root@localhost openldap]#
حالا اگه دوباره از پایگاه داده query بگیرم، مدیر اضافه شده
[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)"# extended LDIF # # LDAPv3 # base <dc=itpro,dc=com> with scope subtree # filter: (objectclass=*) # requesting: ALL # # itpro.com dn: dc=itpro,dc=com objectClass: dcObject objectClass: organization o: itpro dc: itpro # Manager, itpro.com dn: cn=Manager,dc=itpro,dc=com objectClass: organizationalRole cn: Manager # search result search: 2 result: 0 Success # numResponses: 3 # numEntries: 2 [root@localhost openldap]#
حالا که سازمان درست شد، میخوام بخش های مختلف سازمان رو اضافه کنم. مثلا سازمان 3 تا دپارتمان داره.
dn: ou=linux,dc=itpro,dc=com ou: linux objectclass: organizationalunit dn: ou=software,dc=itpro,dc=com ou: software objectclass: organizationalunit dn: ou=hardware,dc=itpro,dc=com ou: hardware objectclass: organizationalunit
اگه space نذارید بین خط ها کار نمیکنه، آخر خط ها هم space بزنید بازم کار نمیکنه !!! کلا ldap خیلی گیره سر این چیزا. میبینید سر یه space توی کانفیگ فایل، کلا سرور آپ نمیشه !!!
حالا دپارتمان ها رو اضافه میکنم
[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -h localhost -W -x -f build_dep.ldif Enter LDAP Password: adding new entry "ou=linux,dc=itpro,dc=com" adding new entry "ou=software,dc=itpro,dc=com" adding new entry "ou=hardware,dc=itpro,dc=com" [root@localhost openldap]#
پایگاه دادم اینجوری شد
[root@localhost openldap]# ldapsearch -x -b "dc=itpro,dc=com" "(objectclass=*)" # extended LDIF # # LDAPv3 # base <dc=itpro,dc=com> with scope subtree # filter: (objectclass=*) # requesting: ALL # # itpro.com dn: dc=itpro,dc=com objectClass: dcObject objectClass: organization o: itpro dc: itpro # Manager, itpro.com dn: cn=Manager,dc=itpro,dc=com objectClass: organizationalRole cn: Manager # linux, itpro.com dn: ou=linux,dc=itpro,dc=com ou: linux objectClass: organizationalUnit # software, itpro.com dn: ou=software,dc=itpro,dc=com ou: software objectClass: organizationalUnit # hardware, itpro.com dn: ou=hardware,dc=itpro,dc=com ou: hardware objectClass: organizationalUnit # search result search: 2 result: 0 Success # numResponses: 6 # numEntries: 5 [root@localhost openldap]#
حالا میخوام یک کارمند اضافه کنم. یک فایل جدید با ldif درست میکنم.
dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com cn: Mohammad Nasiri sn: UNITY mail: unity@itpro.com departmentNumber: software telephoneNumber: 203-543-8958 objectclass: inetOrgPerson
حالا اضافه میکنیم به پایگاه داده:
[root@localhost openldap]# ldapadd -D "cn=Manager,dc=itpro,dc=com" -h localhost -W -x -f build_worker.ldif Enter LDAP Password: adding new entry "cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com" [root@localhost openldap]#
محمد نصیری اضافه شد !!! :))) این یه تیکه از خروجی دستور ldapsearch هستش. دقت کنید که هر object یک cn منحصر به فرد داره.
# Mohammad Nasiri, software, itpro.com dn: cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com cn: Mohammad Nasiri sn: UNITY mail: unity@itpro.com departmentNumber: software telephoneNumber: 203-543-8958 objectClass: inetOrgPerson
دقت کنید که برای یک شخص در سازمان و یک بخش از سازمان از objectclass های متفاوتی استفاده کردم. پس هر برنامه ای نصب کردید یا خواستیذ کلا چیزی به پایگاه داده اضافه کنید باید بدونید objectclass اون چیه.
حالا قراره یک نفر رو از سازمان خارج کنیم!!!
[root@localhost openldap]# ldapdelete -D "cn=Manager,dc=itpro,dc=com" -W -x -v "cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com" Enter LDAP Password: deleting entry "cn=Mohammad Nasiri,ou=software,dc=itpro,dc=com" [root@localhost openldap]#
با دستور ldapmodify هم میتونید اطلاعات یک object رو تغییر بدید. دستور ldapsearch رو هم میشه محدودش کرد که کجا رو جستجو کنه. از regex و wildcard و این جور چیزا میشه توش استفاده کرد. به عهده خودتون اینا. بحث ldap خیلی گستردس، اینجا فقط در حد اینکه یه ذهنیتی ایجاد بشه صحبت کردیم. اگر بخوایم ldap server رو با Active Directory و یا خود کاربران لینوکسی ترکیب کنیم و یا از سیستم های احراز هویت و این جور چیزا استفاده کنیم، وارد یکی از حوزه های بزرگ لینوکس به نام mix environment میشیم که موضوعش درمورد integrate کردن سیستم های لینوکسی و ماکروسافته.
بعضی اوقات میخواهیم که یک کار در زمان مشخص انجام شود و یا برنامه ای سر زمان بندی خاص اجرا شود. به این کار automate کردن یک برنامه یا کار گقته میشود. ابزار های مختلفی برای این کار که هر ابزار ویژگی خاص خود را دارد، وجود دارد.
1- استفاده از cron
2- استفاده از at
3- استفاده از Anacron
4- استفاده از batch
System Cron Jobs
هم کاربران عادی سیستم میتوانند برنامه ای تنظیم کنند تا دستورات و کارهایشان طبق یک زمان بندی انجام شود، و هم مدیر سیستم میتواند کارهای سیستم را زمان بندی کند. مدیر سیستم با استفاده از فایل etccrontab و مسیر etccron.d که فایل های درون آن طبق فرمت crontab اجرا میشوند، کارهای سیستم را زمان بندی میکند. 4 پوشه مهم دیگر هم در etc وجود دارد به نام های cron.daily و cron.weekly و cron.monthly و cron.hourly که اسکریپت های داخل آنها در زمان های مشخص شده اجرا میشوند.
فایل crontab را باز کنید و به محتویات درون آن دقت کنید.
[root@centos6 ~]# cat /etc/crontab SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # For details see man 4 crontabs # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed [root@centos6 ~]#
این فایل 7 ستون دارد که هر کدام معنی خاصی دارد. ستون اول دقیقه را مشخص میکند. مثلا اگر 5 باشد یعنی 5 دقیقه از سر ساعت گذشته. ستون دوم ساعت را مشخص میکند. مثلا 20 یعنی ساعت 8 شب. ستون سوم روز را مشخص میکند. مثلا 10 یعنی روز دهم از ماه. ستون چهارم هم ماه را مشخص میکند. مثلا 2 باشد یعنی فوریه. ستون پنجم هم هم روز هفته را مشخص میکند. روز های هفته از دوشنبه شروع میشوند. به معنی همه است. مثلا اگر ستون ماه بود یعنی هر ماه. ستون بعدی نام کاربری است که این برنامه را اجرا میکند. ستون آخر هم مسیر فایلی است که میخواهیم اجرا شود.
برای کاربران عادی فایل های cron در مسیر varspoolcroncrontabs قرار دارند. کاربر با دستور crontab -e میتواند یک job جدید درست کند. بعد از وارد کردن دستور صفحه ای مانند vim باز میشود. این صفحه خالی باید با فرمت فایل crontab پر شود ولی 6 ستون دارد نه 7 تا. دیگه نام کاربر لازم نیست. چون مشخص دیگه. هر کاربر این دستور رو بزنه مشخص برای کی داره نوشته میشه. مثلا اطلاعات زیر رو وارد میکنیم.
*/5 8-16 8 8 1 ls /tmp
ستون اول 2 تا کاراکتر رو ترکیب کردم یعنی هر 5 دقیقه. اگه 5 خالی میذاشتم فقط سر 5 دقیقه از ساعت گذشته اجرا میشد. این خاصیت رو با استفاده از * ایجاد کردم. ستون بعدی یعنی از ساعن 8 صبح تا 4 بعد از ظهر. ستون بعدی یه ستاره گذاشتم یعنی هر روز از ماه . ستون بعدش هم ستاره یعنی هر ماه. ستون بعدش هم 1 یعنی روز اول هفته یعنی دوشنیه. پس هر 5 دقیقیه ساعت 8 تا 16 روز دوشنبه توی کل سال این برنامه اجرا میشه. حالا آدرس برنامه ندادم. گفتم واسه مسیر tmp/ دستور ls رو اجرا کن.
با دستور crontab و سویچ l- لیست job ها رو میبینید و با سویچ r- میتونید پاکشون کنید.
[mohammad@centos6 ~]$ crontab -l */5 8-16 * * 1 ls /tmp [mohammad@centos6 ~]$ crontab -r [mohammad@centos6 ~]$ crontab -l no crontab for mohammad [mohammad@centos6 ~]$
میتونید دستوراتی که میخواین اجرا بشن رو توی یک فایل بنویسید و آدرسشو در ستون آخر وارد کنید، که معمولا همین کار رو میکنن.
برای مثال اگر بخوام از سیستم backup بگیرم میشه بصورت زیر انجامش داد.
[root@centos6 ~]# cd /etc/cron.d/ [root@centos6 cron.d]# vim daily-backup [root@centos6 cron.d]# cat daily-backup 30 20 * * 1-5 root /root/backup.sh [root@centos6 cron.d]# ls 0hourly daily-backup raid-check sysstat [root@centos6 cron.d]# [root@centos6 cron.d]#
توی فایل backup.sh دستورات مربوط به پشتیبان گیری نوشته میشه. حالا این مثال فقط با دسترسی کاربر ارشد بود. با کاربر معمولی میتونید دستورات رو توی یه فایل مثلا در home directory خودتون ذخیره کنید و بعدش با دستور crontab و سویچ e- زمان بندی دلخواهتون رو تنظیم کنید و در ستون آخر آدرس اون فایل برنامتون رو بدید.
Anacron
دیدیم که با cron میتوان طبق یک زمان بندی دستورانی را اجرا کرد. اما اگر سیستم خاموش شود، دیگر سیستمی برای چک کردن کارهایی که باید انجام میشد ولی انجام نشده ، وجود ندارد و سیستم تا زمان مقرر بعدی صبر میکند تا دوباره طبق زمان بعدی کار ها را انجام دهد. در صورتی که با Anacron میتوان مشخص کرد که چند دقیقه بعد از روشن شدن سیستم بررسی کند چه تعداد از کار هایی که باید انجام میشد، انجام شده یا نشده.
فایل کانفیگ Anacron در مسیر زیر وجود دارد.
[root@centos6 ~]# cat /etc/anacrontab # /etc/anacrontab: configuration file for anacron # See anacron(8) and anacrontab(5) for details. SHELL=/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root # the maximal random delay added to the base delay of the jobs RANDOM_DELAY=45 # the jobs will be started during the following hours only START_HOURS_RANGE=3-22 #period in days delay in minutes job-identifier command 1 5 cron.daily nice run-parts /etc/cron.daily 7 25 cron.weekly nice run-parts /etc/cron.weekly @monthly 45 cron.monthly nice run-parts /etc/cron.monthly [root@centos6 ~]#
ستون اول period نام دارد. اگر عدد 1 باشد ینی هر روز، اگر عدد 7 باشد یعنی هقتگی و اگر 30 باشد یعنی ماهانه. میتوان از کلماتی مثل monthly@ هم استفاده کرد. سوت دوم delay نام دارد یعنی چند دقیقه بعد از روشن شدن سیستم صبر کند. ستون سوم job identifier است. این ستون اصطلاحا آدرس فایل timestamp را مشخص میکند که در مسیر varspool قرار دارد. برای هر job این فایل باید یکتا باشد. درون این فایل های timestamp رشته ای وجود دارد که نشان میدهد آخرین بار چه موقع job انجام شده. ستون چهارم هم مسیر فایل که باید اجرا شود را مشخص میکند.
[root@centos6 ~]# ls /var/spool/anacron/ cron.daily cron.monthly cron.weekly [root@centos6 ~]# cat /var/spool/anacron/cron.daily 20160826 [root@centos6 ~]# cat /var/spool/anacron/cron.monthly 20160727 [root@centos6 ~]# cat /var/spool/anacron/cron.weekly 20160825 [root@centos6 ~]#
برای مثال اگر خط زیر را در anacrontab وارد کنیم یعنی هر هفته برنامه ای که بهت دادم رو اجرا کن و اگر سیستم خاموش بود و اجرا نشد 15 دقیقه بعد از روشن شدن سیستم چک کن ببین اجرا شده یا نه اگر اجرا نشذه بود همین الان اجراش کن.
7 15 test.daily /home/mohammad/backup.sh
خوب حالا اگه سیستم روشن باشه چی ؟؟ کی باید این برنامه اجرا بشه ؟؟
[root@centos6 ~]# grep START /etc/anacrontab START_HOURS_RANGE=3-22 [root@centos6 ~]#
اینکه کی برنامه اجرا بشه توسط متغیر بالا در فایل کانفیگ anacron مشخص میشه. معنی این خط میشه از 3 بامداد تا 10 شب. میتونید زمان دلخواه خودتون رو بهش بدبد. شکل زیر رو از یه سایت خارجی پیدا کردم. تفاوت cron و Anacron رو گفته. خیلی قشنگ نوشته. فک نمیکنم احتیاج به ترجمه و یا توضیح اضافه من باشه.
At و Batch
این دو دستور خیلی جالبن. بصورت پیش فرض at نصب نیست. ( واسه من که نبود ) با دستور yum install at نصبش کنید. کار کردن با این 2 تا دستور خیلی راحته. فقط مینویسید at سپس زمان مورد نظر. بعدش شکل prompt عوض میشه و میتونید دستورات رو وارد کنید. آخرش هم با کنترل d خارج میشه. با دستور atq لیست job هایی که قراره اجرا بشه رو میشه دید. اون عدد اولش شماره شناسایی اون job هستش. اولش هیچی توی job نبود. بعدش یه خط دستور نوشتم. واسه دستور at حتی چیزی مثل at noon tomorrow هم قابل قبوله. با دستور atrm و شماره job میتونید پاکش کنید.
[root@centos6 ~]# [root@centos6 ~]# atq [root@centos6 ~]# at 11 am tomorrow at> ls /etc/ > ~/file_at at> <EOT> job 1 at 2016-08-27 11:00 [root@centos6 ~]# atq 1 2016-08-27 11:00 a root [root@centos6 ~]# at 3 pm 23 dec at> rm -rf ~/sile.txt at> <EOT> job 2 at 2016-12-23 15:00 [root@centos6 ~]# atq 2 2016-12-23 15:00 a root 1 2016-08-27 11:00 a root [root@centos6 ~]# atrm 1 [root@centos6 ~]# atrm 2 [root@centos6 ~]# atq [root@centos6 ~]# [root@centos6 ~]#
دستور batch هم دقیقا مث at میمونه فقط با یک تفاوت. زمانی اجرا میشه که load average سیستم کمتر از 0.8 باشه. برای دستور batch دیگه زمان و تاریخ مشخص نمیکنیم. به محض اینکه load average سیستم کمتر از 0.8 بشه دستورات اجرا میشن.
[root@centos6 ~]# batch at> ls /boot > ~/boot_file at> <EOT> job 3 at 2016-08-26 21:26 [root@centos6 ~]# atq [root@centos6 ~]# [root@centos6 ~]# cat ~/boot_file config-2.6.32-279.el6.i686 efi elf-memtest86+-4.10 grub initramfs-2.6.32-279.el6.i686.img lost+found memtest86+-4.10 symvers-2.6.32-279.el6.i686.gz System.map-2.6.32-279.el6.i686 vmlinuz-2.6.32-279.el6.i686 [root@centos6 ~]# [root@centos6 ~]# [root@centos6 ~]# uptime 21:27:49 up 1 day, 1:16, 3 users, load average: 0.00, 0.00, 0.00 [root@centos6 ~]# [root@centos6 ~]#
با توضیحاتی که گفتیم دستورات بالا کاملا واضحن !! چون تقریبا ، تقریبا که نه ، دقیقا انگار هیچ لودی روی سیستم من نیست، دستوری که به batch دادم اجرا شد بلافاصله. دستورات batch هم مثل at با atq و atrm مدیریت میشن.
ضمیمه
در حالت عادی هر کسی میتونه برای خودش از دستورات at و cron استفاده کنه. برای اینکه این دستورات رو برای کاربران محدود کنیم میتونیم 2 دسته فایل به اسم های زیر درست کنیم.
/etc/cron.allow or /etc/at.allow /etc/cron.deny or /etc/at.deny
اگر فایل های نوع اول رو درست کنیم، فقط کسانی که اسمشون توی لیسته میتونن از دستورات استفاده کنن و بقیه نمیتونن.اگر فایل های نوع دوم رو درست کنیم، فقط کسانی که اسمشون توی لیسته نمیتونن از دستورات استفاده کنن و بقیه میتونن.
در این جلسه میخوایم کانفیگ فایروال لینوکس یعنی iptable رو یاد بگیریم. در کل میتوان کارهایی که فایروال انجام میدهد را در 5 دست کلی تقسیم بندی کرد.
1- NAT
2- PAT
3- Filtering
4- QOS
5- Mangling
تو مورد فیلترینگ مثلا میگیم فلان آی پی به فلان پورت دسترسی نداشته باشه، یا توی nat آی پی ها به هم تبدیل میشن. pat هم شبیه nat هستش تا حدودی، فقط با پورت کار میکنه. توی فوروارد کردن پورت ها کاربرد داره، مثلا توی کشینگ. qos هم برای بررسی لود سیستم استفاده میشه، مثلا چند درصد پکت های وب سرورم دراپ شده یا چند درصد پکت های فلان آی پی دراپ شده. mangling هم فقط به درد حال گیری از خود شاخ پندارایی میخوره که هیچی از لینوکس و شبکه بلد نیستن، بعد میرن چهار تا تریک کالی یاد میگیرن و اسم خودشونو میذارن هکر. این mangling میاد اتک هایی که به سیستم زده میشه رو میگیره، به خود حمله کننده برمیگردونه و اگه سیستم حمله کننده در برابر اتک خودش مقاوم نباشه، میره رو هوا.
برای اینکه ببینید iptable در چه وضعیتی قرار داره دستور زیر را وارد کنید.
[root@centos6 ~]# service iptables status Table: filter Chain INPUT (policy ACCEPT) num target prot opt source destination Chain FORWARD (policy ACCEPT) num target prot opt source destination Chain OUTPUT (policy ACCEPT) num target prot opt source destination [root@centos6 ~]#
اگه iptables روشن نبود با دستور service iptables start روشنش کنید. اگر سیستمتون آموزشیه و چیزی به غیر از خروجی بالا میبینید، دستور iptables -F رو بزنید تا تمام rules های فایروال پاک بشه. میخوایم از صفر شروع کنیم فایروال رو کانفیگ کنیم. به خروجی دستورات زیر دقت کنید
[root@centos6 ~]# iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination [root@centos6 ~]# iptables -L -t nat Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination [root@centos6 ~]# iptables -L -t mangle Chain PREROUTING (policy ACCEPT) target prot opt source destination Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination [root@centos6 ~]# iptables -L -t filter Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination [root@centos6 ~]#
اگر دستور iptables رو با سویچ L- بزنم بصورت پیش فرض جدول filtering رو نشون میده. بعدش با سویچ t- جدول های دیگه رو چاپ کردم. اینا جداول پیش فرض iptable هستن که نمیتونید پاکشون کنید ولی میتونید در موارد خاص برای خودتون جدول هم بسازید ولی در بیشتر موارد با همین جدولا کارمون راه میفته. بیشتر در محیط های enterprise که لود خیلی زیاده توجیه داره جدول جدا نوشتن که سرعت پاسخ گویی سیستم پایین نیاد و یا بخوایم برای یک شرایط خاص تدابیر خاصی درنظر بگیریم.
هر کذوم از این جدول ها chain دارن. توی chain ها rule ها رو مینویسبم. chain ها یه جور طبق بندی محسوب میشه. الان جدول filter من 3 تا chain داره به نام های input و output و forwarding . توی این chain ها policy های دسترسی نوشته میشه. هر پکتی وارد سیستم میشه از این policy ها عبور میکنه. در کل 2 استراتژیک کلی برای کانفیگ فایروال داریم. اول اینکه همه چی بسته باشه، چیزایی که میخوام رو باز میکنم. دوم اینکه همه چی باز باشه و چیزایی که نمیخوام رو میبیندم. مورد اول معمولا استغاده میشه. کلا همه چی رو جلوشو میگریم، بعدش تک تک به سرویس هایی که راه اندازی میکنم، اجازه دسترسی میدم.
این 3 تا chain که گفتم از اسمش مشخصه که روی چی حساسن. حالا میام استراتژی مورد اول رو پیاده سازی میکنم. همه چی رو میبندم. خود جلوی جیزی رو گرفتن 2 حالت داره، reject کردن و drop کردن. فرقشون اینه که drop انجام بشه log نمیندازه ولی reject اتفاق بیفته log میندازه.الان policy پیش فرض accept هست، ینی همه چی بازه. حالا با دستور زیر policy رو drop میکنم.
[root@centos6 ~]# iptables -P INPUT DROP [root@centos6 ~]# iptables -P OUTPUT DROP [root@centos6 ~]# iptables -P FORWARD DROP [root@centos6 ~]# iptables -L -t filter Chain INPUT (policy DROP) target prot opt source destination Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination [root@centos6 ~]#
الان دیگه حتی پینگ هم نمیشه کرد. گفتم اگر خواستیم میتونیم chain درست کنیم علاوه بر chain های پیش فرض. حالا اگه 1000 خط rule نوشته باشم، بیخود همه هزار خط خونده میشه تا برسه مثلا به خطی که ssh رو اجازه عبور میده. در این مورد میام یه chain درست میکنم واسه ssh و به جای اینکه اون هزار خط چک بشه، میگم اگه مثلا پورت مقصدت 22 هستش jump کن توی chain مربوط به ssh. حالا میخوام همین کار رو بکنم. ابتدا یک chain درست میکنم و میگم هر چی مربوط به پورت 22 بود jump کنه توی این chain. توی chain میگم چه کار کنه باهاش، مثلا اجازه بده یا هرچی.
SSH
@centos6 ~]# iptables -N SSH_RULES [root@centos6 ~]# iptables -A INPUT -p tcp --dport 22 -j SSH_RULES [root@centos6 ~]# iptables -A OUTPUT -p tcp --sport 22 -j SSH_RULES [root@centos6 ~]# iptables -A SSH_RULES -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT [root@centos6 ~]# iptables -A SSH_RULES -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT [root@centos6 ~]# iptables -L -t filter Chain INPUT (policy DROP) target prot opt source destination SSH_RULES tcp -- anywhere anywhere tcp dpt:ssh Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination SSH_RULES tcp -- anywhere anywhere tcp spt:ssh Chain SSH_RULES (2 references) target prot opt source destination ACCEPT tcp -- anywhere anywhere tcp dpt:ssh state NEW,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp spt:ssh state ESTABLISHED [root@centos6 ~]#
خط اول یک chain درست کردم. اسمش هر چی میتونه باشه. خط دوم توی جدول input گفتم که هر چی اومد و پورت مقصدش 22 بود، به ssh-rules مراجعه کن. خط بعد هم همینکار واسه جدول output یعنی هر چی خواست خارج بشه که پورت مبداش 22 بود به ssh-rules مراجعه کن. سویچ A- یعنی append و j- یعنی jump و p- یعنی پروتکل. خط سوم و چهارم توی ssh-rules اضافه شده. یکی برای ورود و یکی برای خروج. میتونستم interface رو هم محدود کنم مثلا برای ورود مینوشتم i- eth1 یعنی فقط از eth1 و برای خروج هم مث همین فقط با سویچ o-. اینطوری دیگه از هیچ اینترفیس دیگه ای نمیشد ssh زد. اگر هم میخواستید که از یک شبکه خاص فقط بشه ssh زد، با سویچ s- و رنج آی پی، اون شبکه رو مجاز میکردیم.
حالا هر چی کد نوشتیم توی حافظه جاری سیستم قرار داره و اگه سیستم ریست بشه یا سرویس رو restart کنیم، همه چی پاک میشه. برای ذخیره دستور زیر را وارد کنید. به مسیر کانفیگ فایل پیش فرض دقت کنید.
[root@centos6 ~]# /etc/init.d/iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables: [ OK ] [root@centos6 ~]#
HTTP HTTPS
حالا میخوام دسترسی به وب سرور رو باز کنم. اینو متفاوت با قبلی مینویسیم. دیگه براش chain جدا ننوشتم.
[root@centos6 ~]# iptables -A INPUT -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT [root@centos6 ~]# iptables -A OUTPUT -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT [root@centos6 ~]# iptables -L -t filter Chain INPUT (policy DROP) target prot opt source destination SSH_RULES tcp -- anywhere anywhere tcp dpt:ssh ACCEPT tcp -- anywhere anywhere tcp dpt:http state NEW,ESTABLISHED Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination SSH_RULES tcp -- anywhere anywhere tcp spt:ssh ACCEPT tcp -- anywhere anywhere tcp spt:http state ESTABLISHED Chain SSH_RULES (2 references) target prot opt source destination ACCEPT tcp -- anywhere anywhere tcp dpt:ssh state NEW,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp spt:ssh state ESTABLISHED [root@centos6 ~]#
حالا یکم سویچ هاشو هم یاد بگیریم، با سویچ R- میشه یک خط رو جایگزین کرد. میتونید insert هم بکنید با سویچ I-
[root@centos6 ~]# iptables -R OUTPUT 2 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT [root@centos6 ~]# iptables -R INPUT 2 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT [root@centos6 ~]# [root@centos6 ~]# iptables -L -t filter Chain INPUT (policy DROP) target prot opt source destination SSH_RULES tcp -- anywhere anywhere tcp dpt:ssh ACCEPT tcp -- anywhere anywhere multiport dports http,https state NEW,ESTABLISHED Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy DROP) target prot opt source destination SSH_RULES tcp -- anywhere anywhere tcp spt:ssh ACCEPT tcp -- anywhere anywhere multiport sports http,https state ESTABLISHED Chain SSH_RULES (2 references) target prot opt source destination ACCEPT tcp -- anywhere anywhere tcp dpt:ssh state NEW,ESTABLISHED ACCEPT tcp -- anywhere anywhere tcp spt:ssh state ESTABLISHED [root@centos6 ~]#
ICMP
حالا میخوام ما بتونیم بقیه رو پینگ کنیم ولی بقیه نتونن ما رو پینگ کنن.
[root@centos6 ~]# iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT [root@centos6 ~]# iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT [root@centos6 ~]# ping 192.168.1.33 PING 192.168.1.33 (192.168.1.33) 56(84) bytes of data. 64 bytes from 192.168.1.33: icmp_seq=1 ttl=128 time=1.61 ms 64 bytes from 192.168.1.33: icmp_seq=2 ttl=128 time=0.544 ms 64 bytes from 192.168.1.33: icmp_seq=3 ttl=128 time=0.450 ms ^C --- 192.168.1.33 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2871ms rtt min/avg/max/mdev = 0.450/0.870/1.618/0.530 ms [root@centos6 ~]#
میتونم از توی centos که روی vm نصبه ویندوزم رو پینگ کنم ولی از روی ویندوزم نمیتونم centos رو پینگ کنم.
اگه خواستید پینگ از بیرون باز باشه:
[root@centos6 ~]# iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT [root@centos6 ~]# iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
عکس اینو دیگه نمیزارم جا میگیره!!!
گفتم چطوری تنظیمات iptable رو باید ذخیره کنید تا با راه اندازی محدد ، تنظیمات حفظ بشن. مسیر جایی که ذخیره میشد رو هم دیدید در خروجی دستور. حالا اگه خواستم یه backup برای خودم بگیرم دستور زیر رو میزنم و اگه خواستم از backup برای restore کردن iptable استفاده کنم، دستور بعدیشو.
[root@centos6 ~]# iptables-save > ~/iptable.backup [root@centos6 ~]# iptables-restore ~/iptable.backup [root@centos6 ~]#
صفحه manual رو حتما بخونید. تمام سویچ ها برای insert و delete و flush کردن و ... رو کامل نوشته. یادتون باشه که با دستور iptable و سویچ F- تمام تنظیمات پاک میشه و از کانفیگ پیش فرض بالا میاد. در ادامه یک سری از دستورات مهم iptable رو نوشتم.
1. Delete Existing Rules iptables -F (or) iptables --flush 2. Set Custome Chain Policies iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT DROP 3. Block a Specific ip-address BLOCK_THIS_IP="x.x.x.x" iptables -A INPUT -s "$BLOCK_THIS_IP" -j DROP iptables -A INPUT -i eth0 -s "$BLOCK_THIS_IP" -j DROP iptables -A INPUT -i eth0 -p tcp -s "$BLOCK_THIS_IP" -j DROP 4. Allow ALL Incoming SSH iptables -A INPUT -i eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT 5. Allow Incoming SSH only from a Sepcific Network iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT 6. Allow Incoming HTTP and HTTPS iptables -A INPUT -i eth0 -p tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT iptables -A INPUT -i eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT 7. Combine Multiple Rules Together using MultiPorts iptables -A INPUT -i eth0 -p tcp -m multiport --dports 22,80,443 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp -m multiport --sports 22,80,443 -m state --state ESTABLISHED -j ACCEPT 8. Allow Outgoing SSH iptables -A OUTPUT -o eth0 -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT 9. Allow Outgoing SSH only to a Specific Network iptables -A OUTPUT -o eth0 -p tcp -d 192.168.100.0/24 --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A INPUT -i eth0 -p tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT 10. Allow Outgoing HTTPS iptables -A OUTPUT -o eth0 -p tcp --dport 443 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A INPUT -i eth0 -p tcp --sport 443 -m state --state ESTABLISHED -j ACCEPT 11. Load Balance Incoming Web Traffic iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 0 -j DNAT --to-destination 192.168.1.101:443 iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 1 -j DNAT --to-destination 192.168.1.102:443 iptables -A PREROUTING -i eth0 -p tcp --dport 443 -m state --state NEW -m nth --counter 0 --every 3 --packet 2 -j DNAT --to-destination 192.168.1.103:443 12. Allow Ping from Outside to Inside iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT 13. Allow Ping from Inside to Outside iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT 14. Allow Loopback Access iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT 15. Allow Internal Network to External network. iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT 16. Allow outbound DNS iptables -A OUTPUT -p udp -o eth0 --dport 53 -j ACCEPT iptables -A INPUT -p udp -i eth0 --sport 53 -j ACCEPT 17. Allow NIS Connections iptables -A INPUT -p tcp --dport 111 -j ACCEPT iptables -A INPUT -p udp --dport 111 -j ACCEPT iptables -A INPUT -p tcp --dport 853 -j ACCEPT iptables -A INPUT -p udp --dport 853 -j ACCEPT iptables -A INPUT -p tcp --dport 850 -j ACCEPT iptables -A INPUT -p udp --dport 850 -j ACCEPT iptables -A INPUT -i eth0 -p tcp -s 192.168.101.0/24 --dport 873 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 873 -m state --state ESTABLISHED -j ACCEPT 19. Allow MySQL connection only from a specific network iptables -A INPUT -i eth0 -p tcp -s 192.168.100.0/24 --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT 20. Allow Sendmail or Postfix Traffic iptables -A INPUT -i eth0 -p tcp --dport 25 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 25 -m state --state ESTABLISHED -j ACCEPT 21. Allow IMAP and IMAPS iptables -A INPUT -i eth0 -p tcp --dport 143 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 143 -m state --state ESTABLISHED -j ACCEPT iptables -A INPUT -i eth0 -p tcp --dport 993 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 993 -m state --state ESTABLISHED -j ACCEPT 22. Allow POP3 and POP3S iptables -A INPUT -i eth0 -p tcp --dport 110 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 110 -m state --state ESTABLISHED -j ACCEPT The following rules allow POP3S access. iptables -A INPUT -i eth0 -p tcp --dport 995 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 995 -m state --state ESTABLISHED -j ACCEPT 23. Prevent DoS Attack iptables -A INPUT -p tcp --dport 80 -m limit --limit 25/minute --limit-burst 100 -j ACCEPT 24. Port Forwarding iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 --dport 422 -j DNAT --to 192.168.102.37:22 iptables -A INPUT -i eth0 -p tcp --dport 422 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -o eth0 -p tcp --sport 422 -m state --state ESTABLISHED -j ACCEPT 25. Log Dropped Packets iptables -N LOGGING iptables -A INPUT -j LOGGING iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables Packet Dropped: " --log-level 7 iptables -A LOGGING -j DROP
کارشناس فناوری اطلاعات - Linux Systems Administrator
26 مرداد 1395 این مطلب را ارسال کرده