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

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

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

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

بررسی وجود یک کلمه در یک لیست


می‌خواهم بررسی کنم که آیا یک کلمه در یک لیست وجود دارد( یا یک عنصر عضوی از یک مجموعه هست).

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

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

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

در یک آرایه سنتی معین، تنها روش صحیحِ انجام این کار، اجرای یک حلقه روی تمام عناصر آرایه و کنترل آنها برای عنصر مورد جستجوی شما می‌باشد. فرض کنیم آنچه در جستجوی آن هستیم bar است و لیست ما در آرایه foo قرار دارد:

  •    # Bash
       for element in "${foo[@]}"; do
          [[ $element = $bar ]] && echo "Found $bar."
       done

اگر نیاز دارید این کار را چندین مرتبه در اسکریپت خود انجام بدهید، ممکن است بخواهید منطق آنرا در یک تابع به کار ببرید:

  •    # Bash
       isIn() {
           local pattern="$1" element
           shift
    
           for element
           do
               [[ $element = $pattern ]] && return 0
           done
    
           return 1
       }
    
       if isIn "jacob" "${names[@]}"
       then
           echo "Jacob is on the list."
       fi

یا، اگر می‌خواهید تابع شما شماره شاخص عضوی که عنصر در آن پیدا شده را بازگرداند:

  •    # Bash 3.0 or higher
       indexOf() {
           local pattern=$1
           local index list
           shift
    
           list=("$@")
           for index in "${!list[@]}"
           do
               [[ ${list[index]} = $pattern ]] && {
                   echo $index
                   return 0
               }
           done
    
           echo -1
           return 1
       }
    
       if index=$(indexOf "jacob" "${names[@]}")
       then
           echo "Jacob is the ${index}th on the list."
       else
           echo "Jacob is not on the list."
       fi

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

  •    # Bourne
       set -f
       for element in $foo; do
          if test x"$element" = x"$bar"; then
             echo "Found $bar."
          fi
       done
       set +f

در اینجا کلمه به عنوان هر زیر رشته‌ای که با فضای سفید(یا به طور دقیق‌تر کاراکترهای فعلی در متغیر IFS) مرزبندی شده تعریف می‌شود. دستور ‎ set -f‎ از بسط glob در کلمات داخل لیست پیش‌گیری می‌کند. فعال کردن مجدد بسط glob با‎ (set +f)‎ اختیاری است.

اگر شما در حال کار با bash نسخه 4 یا ksh93 می‌باشید، به آرایه‌های انجمنی دسترسی دارید. اینها به شما اجازه می‌دهند مشکل را تجدید سازمان بدهید -- به جای ساختن لیستی از کلمات که مجاز هستند، شما می‌توانید یک آرایه انجمنی بسازید که در آن کلیدها کلماتی هستند که شما می‌خواهید در نظر بگیرید. مقادیر آنها -- بسته به طبیعت مشکل --می‌توانند با معنی باشند یا نباشند.

  •    # Bash 4
       declare -A good
       for word in "goodword1" "goodword2" ...; do
         good["$word"]=1
       done
    
       # مجاز است $foo کنترل اینکه  آیا 
       if ((${good[$foo]})); then ...

این هم یک روش دستیابی غیر موجه که شما نباید از آن استفاده کنید، اما به خاطر تکمیل مطلب ارائه می‌شود:

  •    # Bash
       if [[ " $foo " = *" $bar "* ]]; then
          echo "Found $bar."
       fi

( مشکل در اینجا آنست که فرض می‌شود space می‌تواند به عنوان جداکننده بین کلمات استفاده شود. عناصر شما ممکن است شامل فاصله باشند، که این روش را ناموفق می‌سازد!)

همان روش، برای پوسته‌های Bourne:

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

همچنین می‌توانید از glob توسعه یافته با printf برای جستجوی کلمه در یک آرایه استفاده کنید. من این را به اندازه کافی تست نکرده‌ام، بنابراین ممکن است در بعضی موقعیت‌ها ناموفق شود --sn18

  •    # Bash
       shopt -s extglob
       # glob تبدیل آرایه به
       printf -v glob '%q|' "${array[@]}"
       glob=${glob%|}
       [[ $word = @($glob) ]] && echo "Found $word"
  • این کُد موقعی که یک عنصر آرایه شامل کاراکتر | باشد شکست می‌خورد. از اینرو، من این را به این پایین میان سایر روشها که به شیوه‌ای با محدودیت مشابه کار می‌کنند انتقال دادم. -- GreyCat

    • printf %q ‎  نیز کاراکتر | را نقل ‌قولی می‌کند، بنابراین احتمالاً اینطور نیست --sn18

grep گنو یک ویژگی ‎ \b‎ دارد که که بنا به گفته برخی بر لبه‌های کلمات مطابقت می‌کند (مرزهای کلمه). ممکن است شخصی سعی کند با کاربرد آن، رویکرد کوتاه‌تر استفاده شده فوق را بازآزمایی نماید، اما این کار توأم با خطر است:

  •    #  یکی از پارامترهای مکانی است؟ 'foo' آیا
       egrep '\bfoo\b' <<<"$@" >/dev/null && echo yes
    
       # یکی از پارامترهای مکانی است؟ '-v'  این جایی است که شکست می‌خورد: آیا
       egrep '\b-v\b' <<<"$@" >/dev/null && echo yes
       # را به صورت یک کلمه جداگانه می‌بیند "v" , \b متأسفانه ‎
       # را به چه جهنمی می‌فرستد ‎"-"‎ کسی نمی‌داند‎
    
       # هست؟ 'array' در آرایه "someword" آیا کلمه 
       egrep '\bsomeword\b' <<<"${array[@]}"
       # باشد نمی‌توانید از این استفاده کنید '-v' همان someword بدیهی است اگر کلمه

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

مقایسه عمده

این شیوه تلاش می‌کند رشته مورد نظر را با تمام محتویات آرایه مقایسه نماید. به طور بالقوه می‌تواند بسیار مؤثر باشد، اما بستگی به جداکننده دارد که نباید در کمیت مورد جستجو یا در آرایه موجود باشد. در اینجا ما از ‎$'\a'‎ ، کاراکتر زنگ، استفاده کرده‌ایم چون بینهایت غیر معمول است.

  •    # usage: if has "element" list of words; then ...; fi
       has() {
         local IFS=$'\a' t="$1"
         shift
         [[ $'\a'"$*"$'\a' == *$'\a'$t$'\a'* ]]
       }

انواع برشمرده(Enumerated types)زیرنویس 1

در ksh93t یا بعد از آن شاید کسی با استفاده از دستور داخلی enum انواع، متغیرها، یا ثابتهای enum ایجاد نماید. اینها به طور مشابه با enumهای C کار می‌کنند(و خصیصه معادل در سایر زبانها). اینها می‌توانند برای محدود نمودن مقادیری که شاید به متغیری اختصاص داده شود، به کار بروند، به طوری‌که از لزوم یک بررسی سنگین در هر نوبتی که یک متغیر آرایه‌ای تنظیم یا ارجاع می‌شود، اجتناب گردد. مانند انواع تولید شده با استفاده از ‎ typeset -T‎، نتیجه یک فرمان enum، فرمان تعریف جدیدی است که می‌تواند برای معرفی اقلام آن نوع به کار برود.

# ksh93
 $ enum colors=(red green blue)
 $ colors foo=green
 $ foo=yellow
ksh: foo:  invalid value yellow‏‏
مترجم: در کُد فوق، به این دلیل خطا صادر می‌شود که ما متغیر را چنان تعریف کرده‌ایم که مقادیر قابل تخصیص به آن، به سه رنگ نامبرده محدود گردیده است

typeset -a‎ همچنین می‌تواند در ترکیب با یک نوع enum برای پذیرفتن ثابتهای enum به عنوان زیرنویس به کار برود.

# ksh93
 $ typeset -a [colors] bar
 $ bar[blue]=test1
 $ typeset -p bar
typeset -a [colors] bar=([blue]=test)
 $ bar[orange]=test
ksh: colors:  invalid value orange

برای مثالهای بیشتر ‎src/cmd/ksh93/tests/enum.sh‎ در منبع AST را ببینید.


  1. مترجم: نوع برشمرده(Enumerated type) از ویژگی‌های زبانهای برنامه نویسی پیشرفته‌ای مانند C است، که در تعریف خود لیست فراگیری از تمام مقادیر ممکن برای آن نوع متغیر را در بر دارد، مانند متغیری با نوع «روزهای هفته» که تعریف آن لیستی شامل هفت عضو با مقادیر شنبه، یکشنبه، و ... می‌باشد. (1)

CategoryShell

پرسش و پاسخ 46 (آخرین ویرایش ‎ 2012-07-24 04:36:07 ‎ توسط ormaaj)


ممانعت دوجانبه


چطور می‌توانم مطمئن شوم که فقط یک نمونه از اسکریپت در یک زمان معین در حال اجرا است(ممانعت دوطرفه)؟

برخی وسائل ممانعت دوجانبه را لازم داریم. یک روش، استفاده از "lock" است: هر تعداد از پردازشها می‌توانند به طور همزمان برای بدست آوردن قفل تلاش نمایند، اما فقط یکی از آنها موفق می‌شود.

چگونه می‌توانیم این کار را با استفاده از اسکریپت‌های شل انجام بدهیم؟ بعضی افراد ایجاد یک فایل قفل، و کنترل وجود آنرا پیشنهاد می‌دهند:

  •  # مثال قفل کردن -- اشتباه‎
     lockfile=/tmp/myscript.lock
     if [ -f "$lockfile" ]
     then                      # قفل قبلاً تصرف شده‎
         echo >&2 "cannot acquire lock, giving up: $lockfile"
         exit 0
     else                      # هیچ کس مالک قفل نیست
         > "$lockfile"         # ایجاد فایل قفل‎
         #...ادامه اسکریپت
     fi

این مثال کار نمی‌کند، زیرا این یک Race Condition می‌باشد: یک دریچه زمانی بین بررسی و ایجاد فایل در مدتی که سایر برنامه‌ها ممکن است عمل کنند. فرض کنید دو پردازش در یک زمان در حال اجرای این کُد می‌باشند. هر دو وجود فایل قفل را بررسی می‌کنند، و هر دو نتیجه می‌گیرند که فایل وجود ندارد. حالا هر دو پردازش گمان می‌کنند که قفل را به دست آورده‌اند -- ناکامی در شرف وقوع است. ما به یک روند بررسی و ایجاد اتمی(تجزیه ناپذیر) نیاز داریم ، و خوشبختانه یکی وجود دارد: mkdir، فرمان ایجاد یک دایرکتوری:

  •  # مثال قفل کردن -- صحیح
     # Bourne
     lockdir=/tmp/myscript.lock
     if mkdir "$lockdir"
     then    # دایرکتوری موجود نبود بنابراین با موفقیت ایجاد شد
         echo >&2 "successfully acquired lock: $lockdir"
         # ادامه اسکریپت
     else
         echo >&2 "cannot acquire lock, giving up on $lockdir"
         exit 0
     fi

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

به جای استفاده از mkdir همچنین می‌توانستیم برنامه ایجاد پیوند نمادین را به کار ببریم، ‎ln -s‎. سومین امکان، داشتن برنامه حذفِ فایل قفلِ از قبل موجود با rm است. قفل با ایجاد مجدد فایل هنگام خروج آزاد می‌شود.

توجه نمایید که نمی‌توانیم از ‎mkdir -p‎ برای ایجاد خودکار اجزا غایب تشکیل دهنده مسیر استفاده کنیم: اگر دایرکتوری از قبل موجود باشد ‎mkdir -p‎ خطایی صادر نمی‌کند، بلکه خصیصه‌ایست که ما برای اطمینان از ممانعت دوطرفه به آن استناد می‌کنیم(مترجم: مقصود، ویژگی اتمی بودن mkdir است).

حالا بیایید خودکار نمودن حذف قفل هنگام خاتمه یافتن اسکریپت را چاشنی این مثال کنیم:

  •  # POSIX (maybe Bourne?)
     lockdir=/tmp/myscript.lock
     if mkdir "$lockdir"
     then
         echo >&2 "successfully acquired lock"
    
         #  حذف می‌شود lockdir ،وقتی اسکریپت به پایان می‌رسد یا موقع دریافت سیگنال ‎
         trap 'rm -rf "$lockdir"' 0    # حذف دایرکتوری موقع پایان یافتن اسکریپت‎
    
         # به طور اختیاری فایلهای موقتی در این دایرکتوری ایجاد می‌شود، چون‎
         #                              .آنها به طور خودکار حذف خواهند شد
         tmpfile=$lockdir/filelist
    
     else
         echo >&2 "cannot acquire lock, giving up on $lockdir"
         exit 0
     fi

این مثال خیلی بهتر است. بازهم این مشکل وجود دارد که وقتی اسکریپت بدون یک سیگنال اخذ شده،(یا سیگنال 9، SIGKILL) خاتمه می‌یابد، قفل کهنه‌ای می‌تواند باقی‌ بماند، یا می‌تواند توسط کاربری(به طور تصادفی یا بدخواهانه) ایجاد بشود، اما این قدم خوبی در جهت ممانعت دوطرفه است. Charles Duffy یک مثال همکارانه دارد که ممکن است مشکل «قفل کهنه» را برطرف نماید .

اگر در لینوکس هستید، می‌توانید از کاربرد‎ flock(1)‎ نیز بهره‌مند شوید. ‎ flock(1)‎ توصیف‌گر فایلی را به یک فایل قفل متصل می‌کند. روشهای چندگانه‌ای برای استفاده از آن موجود است، یک امکان حل مشکلِ نمونه‌های چندتایی، این است:

  •   exec 9>/path/to/lock/file
      if ! flock -n 9  ; then
         echo "another instance is running";
         exit 1
      fi
      #    اکنون این تحت قفل تا بسته شدن 9 اجرا می‌شود‎
      #   (وقتی اسکریپت تمام می‌شود  9 به طور خودکار بسته می‌شود)

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

مباحثه

من معتقدم استفاده از ‎ if (set -C; >$lockfile); then ...‎ کاملاً مطمئن است، اگر که مطمئن‌تر نباشد. منبع Bash از ‎ open(filename, flags|O_EXCL, mode);‎ استفاده می‌کند که تقریباً در تمام سکوها تجزیه‌ناپذیر خواهد بود(به استثنای برخی نگارشهای NFS که در آنها mkdir هم نمی‌تواند اتمی باشد). من نه مسیر نشانه‌های متغیر را دنبال کرده‌ام، که باید محتوی O_CREAT باشند، نه در پوسته‌های دیگر رسیدگی نموده‌ام. من استفاده از این را تا موقعی که شخص دیگری ادعای مرا پشتیبانی نکند، پیشنهاد نمی‌کنم. --Andy753421

  • استفاده از کُدهای ‎set -C‎ با ksh88 کار نمی‌کند. Ksh88 موقعی که شما ‎ ‎noclobber (-C)‎ را تنظیم کنید از O_EXCL استفاده نمی‌کند. --jrw32982

    شما اطمینان دارید که mkdir با اتمی شدن روی NFS مشکل دارد؟ من گمان می‌کنم فقط تحت تأثیر بازشدن واقع شده، اما واقعاً مطمئن نیستم. -- BeJonas 2008-07-24 01:22:59

برای مباحثه بیشتر در باره این موضوعات، مدیریت پردازش را ببینید.


CategoryShell

پرسش و پاسخ 45 (آخرین ویرایش ‎2013-01-11 20:08:22‎ توسط GreyCat)


ایجاد نوار پیشروی


چطور می‌توانم نوار پیشروی ایجاد کنم؟ چگونه می‌توانم موقع کپی یا انتقال فایلها، نمایشگر پیشروی را ببینم؟

آسان‌ترین روش افزودن نوار پیشرفت به اسکریپت خودتان، استفاده از ‎ dialog --gauge‎ است. در اینجا مثالی آورده‌ایم که متکی به ویژگی‌های BASH می‌باشد:

# Bash
# .در شاخه جاری را پردازش می‌کند *.zip تمام فایلهای
files=(*.zip)
dialog --gauge "Working..." 20 75 < <(
   n=${#files[*]}; i=0
   for f in "${files[@]}"; do
   # قرار بدهید "sleep 1"‎ را قرار بدهید، برای تست ‎"$f"‎ در اینجا دستورات پردازش ‎
      echo $((100*(++i)/n))
   done
)

این هم توضیح آن که چکار می‌کند:

  • یک آرایه به نام files با تمام فایلهایی که می‌خواهیم پردازش کنیم، دارای عضو می‌شوند.

  • dialog فراخوانی می‌شود، و ورودی آن به جایگزینی پردازش تغییر مسیر داده می‌شود. ( لوله نیز می‌توانست در اینجا به کار برود، ما می‌بایست به سادگی فرمان dialog و حلقه را برعکس می‌نمودیم.)

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

برای مثالهای بیشتری از کاربرد dialog، پرسش و پاسخ شماره 40 را ببینید.

نوار پیشرفت ساده‌ای نیز می‌تواند بدون استفاده از dialog برنامه ریزی بشود. رویکردهای متفاوت زیادی برای این مورد وجود دارد که بستگی به نوع نمایشی دارد که شما در جستجوی آن می‌باشید.

یک رویکرد سنتی چرخنده است که یک پاره خط در حال دوران را برای دلالت بر مشغول بودن نمایش می‌دهد. این در اصل میزان پیشرفت نیست چون اطلاعاتی در مورد آنکه چطور برنامه به تکمیل شدن نزدیک می‌شود، ارائه نمی‌کند.

مرحله بعدی نمایش یک مقدار عددی بدون حرکت در صفحه نمایش است. استفاده از سطر نورد برای حرکت نشانگر جهت تبدیل شدن به یک سطر(در ترمینال گرافیکی، نه یک دورنگار...) و ننوشتن سطر جدید تا به پایان رسیدن پردازش:

i=0
while ((i < 100)); do
  printf "\r%3d%% complete" $i
  ((i += RANDOM%5+2))
  # را از جایی معنی‌دار دریافت می‌کنیم i البته در زندگی واقعی، ما‎
  sleep 1
done
echo

نکته در اینجا تعیین کننده قالب ‎%3d‎ در printf است. استفاده از فیلد با عرض ثابت برای نمایش اعداد اهمیت دارد، مخصوصاً اگر شمارش معکوس انجام شود(اول 10 و بعد 9 نمایش داده شود). البته ما در اینجا شمارش رو به بالا انجام دادیم، اما به طور عمومی همیشه به این حالت نیست. اگر فیلد با عرض ثابت مطلوب نیست، آنوقت چاپ یک گروه فاصله در انتها می‌تواند به زدودن هر گونه درهم‌برهمی با سطرهای قبلی کمک کند.

اگر بجای یک عدد، یک نوار واقعی مورد نظر باشد، آنوقت شاید شخصی با استفاده از کاراکترهای اسکی آن را رسم کند:

bar="=================================================="
barlength=${#bar}
i=0
while ((i < 100)); do
  # .تعداد قطعات نوار برای رسم کردن
  n=$((i*barlength / 100))
  printf "\r[%-${barlength}s]" "${bar:0:n}"
  ((i += RANDOM%5+2))
  # را از جایی معنی‌دار دریافت می‌کنیم i البته در زندگی واقعی، ما‎
  sleep 1
done
echo

بدیهی است هر کس می‌تواند نواری با طول متفاوت، یا ترکیبی ازمجموعه کاراکترهای متفاوت را انتخاب کند، به عنوان مثال، می‌توانید یک نوار پیشروی رنگی داشته باشید

files=(*)
width=${COLUMNS-$(tput cols)}
rev=$(tput rev)

n=${#files[*]}
i=0
printf "$(tput setab 0)%${width}s\r"
for f in "${files[@]}"; do
   # قرار بدهید "sleep 1"‎ را قرار بدهید، برای تست ‎"$f"‎ در اینجا دستورات پردازش 
   printf "$rev%$((width*++i/n))s\r" " "
done
tput sgr0
echo

هنگام کپی یا انتقال فایلها

نمی‌توانید با‎ cp(1)‎ نمایشگر پیشروی به دست آورید، اما شما می‌توانید :

  • یا خودتان با ابزاری از قبیل pv یا clpbar یکی بسازید

  • یا ابزار دیگری به کار ببرید، به عنوان مثال vcp.

شاید بخواهید از ‎ pv(1)‎ استفاده کنید چون برای بسیاری از سیستم‌ها به صورت بسته‌بندی شده موجود است. در این حالت، اگر تابع یا اسکریپتی برای پوشاندن آن ایجاد نمایید، مناسب است.

برای مثال:

pv "$1" > "$2/${1##*/}"

این فاقد کنترل خطا می‌باشد و از انتقال فایلها پشتیبانی می‌کند.

همچنین می‌توانید از rsync استفاده کنید:

rsync -avx --progress --stats "$1" "$2"

لطفاً توجه نمایید هر دفعه که rsync وارد یک دایرکتوری می‌شود و فایلهای کمتر یا بیشتر از مورد انتظارش پیدا می‌کند، تعداد کل فایلها می‌تواند تغییر نماید، اما حداقل بیش از cp مطلع است. پیشرفت Rsync برای انتقالهای بزرگ با تعداد فایل کم مناسب است.


CategoryShell

پرسش و پاسخ 44 (آخرین ویرایش ‎ 2010-06-25 20:12:14 ‎ توسط MatthiasPopp)


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


چرا این job من در crontab ناموفق است؟
0 0 * * * some command > /var/log/mylog.`date +%Y%m%d`‎

در بسیاری از نگارش‌های crontab، با علامت‎ (%)‎ به طور ویژه‌ای رفتار می‌شود، و بنابراین باید با کاراکتر گریز \ پوشش داده شود:

0 0 * * * some command > /var/log/mylog.`date +\%Y\%m\%d`

برای توضیحات بیشتر مستندات سیستم خود را ببینید(‎crontab(5)‎ یا ‎crontab(1)‎). توجه: در سیستم‌هایی که راهنمای crontab را به دو قسمت تقسیم می‌کنند، ممکن است شما برای خواندن بخش مورد نیاز خود لازم باشد ‎man 5 crontab‎ یا ‎man -s 5 crontab‎ را تایپ کنید.


CategoryShell

پرسش و پاسخ 43 (آخرین ویرایش ‎ 2010-06-25 20:11:42 ‎ توسط MatthiasPopp)


آیا پردازش در حال اجرا می‌باشد؟


چگونه می‌توانم دریابم که یک پردازش هنوز در حال اجرا است؟

فرمان kill برای ارسال سیگنالها به پردازش در حال اجرا به کار می‌رود. به عنوان یک عمل راحت، سیگنال "0" که موجود نیست می‌تواند برای پی بردن به در حال اجرا بودن یک پردازش به کار برود:

# Bourne
myprog &          # برنامه را در پس زمینه آغاز می‌کند
daemonpid=$!      # ...و شماره پردازش آن را ذخیره می‌کند

while sleep 60
do
    if kill -0 $daemonpid       # آیا پردازش هنوز زنده است؟
    then
        echo >&2 "OK - process is still running"
    else
        echo >&2 "ERROR - process $daemonpid is no longer running!"
        break
    fi
done

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

این یکی از آن پرسشهایی است که معمولاً مسئله عمیق‌تری را پوشش می‌دهد. نادر است که شخصی بخواهد بداند آیا پردازشی هنوز واقعاً در حال اجرا می‌باشد برای اینکه چراغ سبز یا قرمزی را برای متصدی روشن کند.

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

# POSIX
while true
do
  myprog && break
  sleep 1
done

این قطعه کُد برنامه myprog را اگر با کُد وضعیت دیگری غیر از صفر خاتمه یابد(نشان دهنده وجود یک اشتباه)، شروع مجدد (restart) می‌کند. اگر کُد وضعیت صفر است(به طور موفقیت آمیز تمام شود) حلقه پایان می‌یابد. (اگر پردازش شما سقوط می‌کند اما کد وضعیت صفر نیز برمی‌گرداند، پس کُد را طبق آن تنظیم کنید.) توجه نمایید که myprog باید در پیش زمینه اجرا شود. اگر به طور خودکار خودش را به حالت daemon می‌برد، شما مست هستید.

برای مباحثه بسیار بهتر در باره این مسائل مدیریت پردازش یا پرسش و پاسخ شماره 33 را ببینید.


CategoryShell

پرسش و پاسخ 42 (آخرین ویرایش ‎ 2012-10-27 10:38:13 ‎ توسط a88-114-128-29)