فصل 15- فرمان‌های داخلی و builtinها

‎15.1‎- فرمانهای کنترل job

برخی از فرمانهای کنترل job زیرین، یک معرف job را به عنوان یک شناسه دریافت می‌کنند. جدول انتهای این فصل را ملاحظه کنید.

jobs

jobهای در حال اجرا در پس‌زمینه را با ارایه شماره job آنها، لیست می‌کند. به اندازه ps سودمند نیست.


اشتباه کردن jobها و پردازش‌ها بسیار بسیار آسان است. برخی builtinها، از قبیل kill‏، disown‏، و wait یک شماره job یا یک شماره پردازش را به عنوان شناسه می‌پذیرند. فرمان‌های fg‏، bg‏، و jobs فقط یک شماره job را قبول می‌کنند.

bash$ sleep 100 &
[1] 1384

bash $ jobs
[1]+  Running                 sleep 100 &

«1» شماره ‎job‎ است (jobها توسط پوسته جاری نگهداری می‌شوند). «1384»‏ ‎PID‎ یا شماره ‎ID‎ پردازش است (پردازش‌ها توسط سیستم نگهداری می‌شوند). برای کشتن این job/پردازش، یا یک ‎kill %1‎ یا یک kill 1384 عمل می‌کند.

باتشکر از ‎S.C.‎


disown

job(ها) را از جدول jobهای فعال پوسته حذف می‌کند.

fg‏، bg

فرمان fg یک job در حال اجرا در پس‌زمینه را به پیش‌زمینه تغییر وضعیت می‌دهد. فرمان bg یک job تعلیق شده را دوباره شروع کرده و آن را در پس‌زمینه اجرا می‌کند. در صورتیکه شماره ‎job‎ تعیین نشده باشد، آنوقت فرمان‌های fg یا bg بر روی job اکنون در حال اجرا، عمل می‌کنند.

wait

اجرای اسکریپت را تا زمانیکه تمام jobهای در حال اجرا در پس‌زمینه خاتمه یافته باشند، یا job یا job با شماره تعین شده یا پردازش با ID مشخص شده به عنوان یک گزینه فرمان، خاتمه یابد، به تعلیق در می‌آورد. سپس وضعیت خروج فرمانی را که در انتظارش مانده برگشت می‌دهد.

شما ممکن است فرمان wait را برای پیش‌گیری از خروج اسکریپت قبل از اتمام اجرای یک job پس‌زمینه (چنین خروجی یک پردازش پدر مرده نگران‌کننده تولید خواهد کرد) به کار ببرید.

مثال ‎15-26‎. انتظار برای پایان یافتن یک پردازش، قبل از پیشروی

#!/bin/bash

ROOT_UID=0   # فقط کاربرانِ با ‎$UID‎ برابر ‎0‎ دارای مزایای ‎root‎ هستند.
E_NOTROOT=65
E_NOPARAMS=66

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "Must be root to run this script."
  # «بچه برو پی کارت، از موقع خوابت گذشته است.»
  exit $E_NOTROOT
fi  

if [ -z "$1" ]
then
  echo "Usage: `basename $0` find-string"
  exit $E_NOPARAMS
fi


echo "Updating 'locate' database..."
echo "This may take a while."
updatedb /usr &                     #       باید به عنوان root اجرا شود.

wait
#               تا وقتی که ‎updatedb‎ تمام شود بقیه اسکریپت را اجرا نشود.
#      قبل از جستجوی نام فایل، بانک اطلاعات به روزرسانی شده را لازم دارید.

locate $1

#    بدون فرمان ‎wait‎، در یک وضعیت وخیم‌تر، در حالیکه ‎updatedb‎ هنوز در حال 
#+.اجرا بود، اسکریپت با رها کردن آن به صورت یک پردازش بی پدر، خارج می‌شد


exit 0

wait می‌تواند به طور اختیاری به عنوان یک شناسه یک معرف job دریافت کند، به عنوان مثال، wait %1‎ یا wait ‎$PID‎‎‎[1]‎‏. جدول ‎job id‎ را ملاحظه کنید.

tip

در داخل یک اسکریپت، اجرای یک فرمان با یک کاراکتر ‎ ampersand (&)‎ در پس‌زمینه، ممکن است موجب شود اسکریپت تا زدن کلید ENTER هنگ شود. به نظر می‌رسد این مورد با فرمانهایی اتفاق می‌افتد که در stdout می‌نویسند. این می‌تواند یک دردسر مهم باشد.

#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
bash$ ./test.sh
Done.
[bozo@localhost test-scripts]$ total 1
-rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
_
 

به طوری که ‎Walter Brameld IV‎ آن را تشریح می‌کند:

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

‎1‎. اسکریپت فرمان را در پس‌زمینه راه‌اندازی می‌کند.
‎2‎. اسکریپت خارج می‌شود.
‎3‎. پوسته اعلان را صادر می‌کند. (مترجم: اما در نمایشگر دیده نمی‌شود چون stdout در اختیار فرمان پس‌زمینه است)
‎4‎. فرمان پس‌زمینه اجرا و نوشتن متن در کنسول را ادامه می‌دهد.
‎5‎. فرمان پس‌زمینه خاتمه می‌یابد.
‎6‎. کاربر در انتهای خروجی اعلانی نمی‌بیند، فکر می‌کند اسکریپت در حال هنگ است.

قرار دادن یک فرمان wait بعد از فرمان پس‌زمینه، مناسب درمان این مورد است.

#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
wait
bash$ ./test.sh
Done.
[bozo@localhost test-scripts]$ total 1
-rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
bash$ 
تغییر مسیر خروجی فرمان به یک فایل یا حتی به ‎/dev/null‎ نیز از این مشکل دوری می‌کند.


suspend

این فرمان دارای اثری مشابه ‎Control-Z‎ است، اما پوسته را به حالت تعلیق در می‌آورد (پردازش والد پوسته باید در یک زمان مناسب آن را ادامه بدهد)‏.

logout

خروج یک پوسته ‎login‎، به طور اختیاری با مشخص کردن یک وضعیت خروج.

times

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

0m0.020s 0m0.020s

این توانایی ارزش نسبتاً محدودی دارد، چون برای شناسایی و سنجش کارایی اسکریپت‌های پوسته رایج نیست.

kill

خاتمه دادن اجباری یک پردازش به وسیله فرستادن یک سیگنال فسخ متناسب ( مثال ‎17-6‎ را ببینید).

مثال ‎15-27‎. اسکریپتی که خودش را می‌کُشد

#!/bin/bash
# self-destruct.sh

kill $$  # .در اینجا اسکریپت پردازش خودش را از بین می‌برد
         # به خاطر بیاورید که ‎$$‎ برابر با ‎PID‎ اسکریپت است.

echo "This line will not echo."
# .در عوض، پوسته یک پیغام «فسخ» به خروجی استاندارد می‌فرستد

exit 0   #خروج عادی؟ خیر!

#  بعد از اینکه این اسکریپت به طور زودهنگام خاتمه
#+        می‌یابد، کدام وضعیت خروج را برگشت می‌دهد؟
#
 bash$ sh self-destruct.sh
 bash$ echo $?
 143
# 143 = 128 + 15 # ^ SIGTERM سیگنال


‎kill -l‎ تمام سیگنال‌ها را لیست می‌کند (همچناکه فایل ‎/usr/include/asm/signal.h‎ لیست می‌کند). یک ‎kill -9‎ یک kill حتمی است، که معمولاً به پردازشی که سرسختانه از کُشته شده با یک ‎kill ساده خودداری می‌کند، خاتمه می‌دهد. گاهی اوقات، یک ‎kill -15 عمل می‌کند. یک پردازش zombie، یعنی یک پردازش فرزند که خاتمه یافته، اما پردازش والد آن هنوز کشته نشده، نمی‌تواند به وسیله یک کاربر login کرده کشته بشود -- شما نمی‌توانید چیزی را قبلاً از مُرده از بین ببرید -- اما init دیر یا زود آن را تصفیه خواهد نمود.

مترجم: پردازش زامبی از بین رفته است اما پدرش از این موضوع بی خبر است بنابراین در جدول پردازش به عنوان یکی از اقلام موجود است. اصلاح این مورد به عهده init است.

killall

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


این دستور به فرمان killall در ‎/usr/bin‎ ارجاع می‌کند، نه به اسکریپت killall در ‎/etc/rc.d/init.d‎


command

فرمان command راهنمای از کارانداختن مستعارها و توابع برای فرمانی است که بلافاصله به دنبال آن می‌آید.

bash$ command ls


این یکی از سه فرمان راهنمای پوسته است که بر پردازش فرمان اسکریپت اثر می‌گذارد. دو فرمان دیگر builtin و enable هستند.


builtin

فراخوانی ‎builtin ‎BUILTIN_COMMAND‎ فرمان ‎BUILTIN_COMMAND‎ را به عنوان یک builtin پوسته اجرا می‌کند، به طور موقت فرمان‌های خارجی سیستم و توابع با همان نام را از کار می‌اندازد.

enable

این یک فرمان builtin پوسته را فعال یا غیرفعال می‌کند. به عنوان یک مثال، enable -n kill‎ فرمان builtin پوسته با نام kill را غیرفعال می‌کند، به طوریکه وقتی Bash پس از آن با kill روبرو شود، فرمان خارجی ‎/bin/kill‎ را احضار می‌کند.

گزینه ‎-a‎ با enable تمام builtinهای پوسته را با نشان دادن اینکه آیا فعال هستند یا خیر، لیست می‌کند. گزینه ‎-f filename‎ اجازه می‌دهد که enable یک builtin را به عنوان یک پیمانه کتابخانه‌ای به اشتراک گذاشته شده ‎(DLL)‎ برای یک فایل object کامپایل شده، بارگیری نماید ‎[2]‎.

autoload

این یک تبدیل Bash از autoloader پوسته ksh است. با autoload به مورد، یک تابع با یک تعریف autoload در اولین احضارش، از یک فایل خارجی بارگیری خواهد گردید. ‎[3]‎ این کار منابع سیستم را صرفه‌جویی می‌کند.

توجه نمایید که autoload بخشی از هسته مرکزی برپاسازی Bash نیست. لازم است به وسیله enable ‎-f‎ در آن بارگذاری بشود (بالا را ببینید)‏.

جدول ‎15-1‎. ‏(تعیین هویت کننده)معرف‌های Job

نمادمعنی
‎‎%N‎‎ شماره Job [N]‎
‎‎%S‎‎ فراخوانی (در خط فرمان) job شروع شوند با رشته S
‎‎%?S‎‎ فراخوانی (از خط فرمان) job شامل رشته S در داخل نام آن
%% job «جاری» (آخرین job متوقف شده در پیش‌زمینه یا شروع شده در پس‌زمینه)
‎‎%+‎‎ job «جاری» (آخرین job متوقف شده در پیش‌زمینه یا شروع شده در پس‌زمینه)
‎‎%-‎‎ آخرین job
‎‎$!‎‎ آخرین پردازش پس‌زمینه

یادداشت‌ها

[1]

البته، این فقط برای پردازش‌های فرزند صادق است.

[2]

به طور نمونه، کد منبع C تعدادی از builtinهای قابل بارگذاری در دایرکتوری ‎/usr/share/doc/bash-?.??/functions‎ قرار دارد.

توجه کنید که گزینه ‎-f‎ با enable قابل حمل به تمام سیستم‌ها نیست.

[3]

همان اثر autoload می‌تواند به وسیله ‎typeset -fu‎ حاصل گردد.