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

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

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

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

ایجاد فایل موقتی به طور بی‌خطر


چطور می‌توانم در یک حالت ایمِن، یک فایل موقتی ایجاد کنم؟

به نظر نمی‌رسد هیچ فرمان منفردی وجود داشته باشد که واقعاً در همه جا کار بکند. tempfile قابل حمل نیست. mktemp به طور وسیع‌تری موجود است( اما باز هم به طور در همه جا حاضر نیست)، فقط ممکن است برای ایجاد فایل از قبل، مستلزم گزینه ‎ -c‎ باشد، یا ممکن است به طور پیش‌فرض فایل را ایجاد کند و اگر ‎ -c‎ فراهم شده باشد، ناموفق گردد. برخی سیستم‌ها هیچ یک از دو فرمان را ندارند(سولاریس و POSIX).

پاسخ سنتی به طور معمول چیزی مانند این بوده:

  #   استفاده نکنید! وضعیت مسابقه!
   tempfile=/tmp/myname.$$
   trap 'rm -f "$tempfile"; exit 1' 1 2 3 15
   rm -f "$tempfile"
   touch "$tempfile"

مشکل با این مورد عبارت است از: اگر فایل از قبل موجود باشد(برای مثال، به عنوان یک لینک به ‎ /etc/passwd‎)، آنوقت ممکن است اسکریپت مواردی را در محل‌هایی بنویسد که نباید نوشته شوند. حتی اگر شما فایل را فوراً قبل از استفاده از آن حذف کنید،، بازهم یکوضعیت مسابقه دارید: شخصی می‌تواند در فاصله مابین دستورات پوسته شما یک لینک بداندیشانه بازتولید نماید.

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

متأسفانه، به نظر نمی‌رسد افراد این پاسخ را دوست داشته باشند. آنها خواستار آن هستند که فایلهای موقتی‌شان در ‎/tmp‎ یا ‎/var/tmp‎ باشند. برای آن افراد، روش پاکیزه‌ای وجود ندارد، بنابراین آنها باید روش هوشمندانه(hack)ای که می‌توانند با آن ادامه بدهند را انتخاب کنند.

ساختن یک دایرکتوری موقتی

در برخی سیستم‌ها(مانند لینوکس):

  • شما دارای فرمان معتبر mktemp می‌باشید و می‌توانید از گزینه ‎-d‎ آن استفاده نمایید، برای اینکه دایرکتوری‌های موقتی ایجاد می‌کند که تنها برای شما قابل دستیابی است، همراه با کاراکترهای تصادفی در نام آنها جهت تقریباً غیر ممکن نمودن حدس زدن پیشاپیشن نام دایرکتوری برای یک مهاجم.

  • می‌توانید فایلهایی با نام طولانی‌تر از ۱۴ کاراکتر در ‎/tmp‎ ایجاد کنید. ‎

  • شما Bash را در دسترس دارید بنابراین از ویژگی‌های مخصوص آن برای این کار استفاده کنید.

   # POSIX در‎

   # تنظیم می‌کند ‎"/tmp"‎  از قبل دارای مقدار نباشد آن را به ‎$TMPDIR‎ فقط در صورتیکه‎
   : ${TMPDIR:=/tmp}

   # ببینیم ‎http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html‎ این صفحه را ‎$TMPDIR‎ می‌توانیم در باره‎

   # ایجاد کنید ‎$TMPDIR‎ یک دایرکتوری موقتی خصوصی در‎
   # وقتی اسکریپت خاتمه می‌یابد دایرکتوری موقتی را حذف کنید‎
   unset temporary_dir
   trap '[ "$temporary_dir" ] && rm -rf "$temporary_dir"' EXIT

   save_mask=$(umask)
   umask 077
   temporary_dir=$(mktemp -d "$TMPDIR/XXXXXXXXXXXXXXXXXXXXXXXXXXXXX") || { echo "ERROR creating a temporary file" >&2; exit 1; }
   umask "$save_mask"

و آنوقت می‌توانید فایلهای ویژه خود را در دایرکتوری موقتی ایجاد کنید.


یک پیشنهاد متفاوت که به فرمان mktemp نیاز ندارد: با استفاده از متغیر RANDOM به صورت زیر، یک دایرکتوری موقتی که بعید است با نام یک دایرکتوری موجود مطابقت بنماید، می‌تواند ایجاد گردد:

   temp_dir=/tmp/$RANDOM
   mkdir "$temp_dir"

این کد یک دایرکتوری به شکل ‎/tmp/20445/‎ ایجاد خواهد نمود‎. برای کاهش احتمال برخورد با نام یک دایرکتوری موجود، متغیر RANDOM می‌تواند چندبار به کار برود، یا با ID پردازش ترکیب بشود:

   temp_dir=/tmp/$RANDOM-$$
   mkdir -m 700 "$temp_dir" || { echo "failed to create temp_dir" >&2; exit 1; }

این کد یک دایرکتوری به صورت ‎/tmp/24953-2875/‎ ایجاد خواهد نمود. این مورد از یک موقعیت مسابقه اجتناب می‌کند، به علت اینکه mkdir همانطور که در پرسش و پاسخ ۴۵ می‌بینیم، تجزیه ناپذیر(اتمی) است. لازم‌الاجراست که شما نتیجهmkdir را کنترل نمایید، در صورتی که در ایجاد دایرکتوری ناموفق باشد ، واضح است که نمی‌توانید پیش بروید.

(برخی سیستم‌ها دارای محدودیت ۱۴ کاراکتر در نام فایل هستند، بنابراین از آزمایش ترکیب بیش از دوبارِ رشته ‎$RANDOM‎ همراه یکدیگر اجتناب کنید. شما برای امنیت خود به تجزیه ‌ناپذیری mkdir استناد می‌کنید، نه برای گمنامی نام تصادفی انتخابی. اگر شخصی دایرکتوری ‎/tmp‎ را با صدهاهزار فایلهای دارای نام عدد تصادفی به منظور انسداد راه شما، پُر کند، با مسایل بزرگتری مواجه هستید.)


به جای RANDOM، می‌توان از awk برای تولید عدد تصادفی به یک روش سازگار با POSIX استفاده نمود:

   temp_dir=/tmp/$(awk 'BEGIN { srand (); print rand() }')
   mkdir -m 700 "$temp_dir"

توجه کنید، به هر حال، آن srand()‎ سرچشمهِ تولید عدد تصادفی، از ثانیه‌ها نسبت به epoch زیرنویس 1 استفاده می‌کند که پیش بینی کردن آن برای یک متخاصم و انجام حمله پرده‌پوشی سرویس(DoS)، به طور مساعدی آسان است.

با ترکیب فوق می‌توانیم به کار ببریم:

   temp_dir=/tmp/"$(awk -v p=$$ 'BEGIN { srand(); s = rand(); sub(/^0./, "", s); printf("%X_%X", p, s) }')"
   mkdir -m 700 "$temp_dir" || { echo '!! unable to create a tempdir' >&2; exit 1; }

چون در awk قالب عددی پیش‌فرض ‎%g‎ می‌باشد که معادل شش رقم بعد از نقطه اعشار است، ما یک دنباله شش رقمی داریم. 999,999 به صورت هگز می‌شود F423F که یک کاراکتر به ما پس می‌دهد، یکی دیگر برای _ و 8 کاراکتر برای پیشوند نمودن pid در سیستم فایل ۱۴ کاراکتری در دسترس است. یک شماره شناسایی پردازش(pid) سی و دو بیتی بدون علامت، حداکثر ۸ رقم هگز خواهد شد، بنابراین مورد فوق در اکثر مکان‌هایی که ممکن است شخصی با چنین سیستم فایلی روبرو گردد، کار می‌کند. و البته چنانکه greycat اشاره نمود، موقع وجود کمبودها، از تنگنا رها می‌شویم.

  • آیا این یک مقداری غیر منطقی نمی‌باشد؟ -- GreyCat

  • نه چندان بیش از رویکرد غیرقابل حمل ارائه شده فوق. نقطه نظر مکرر شما در باره محدودیت ۱۴ کاراکتری در سیستم‌فایلها را جواب می‌دهد، و استفاده از ‎ /tmp‎ که برخی مدیران سیستم ترجیح می‌دهند را میسر می‌سازد، و در صورتی که اسکریپت یک برنامه تعریف شده با یک نام خاص نباشد، می‌تواند سودمند واقع گردد، در آن حالت من موافق هستم که داشتن یک دایرکتوری معین تحت ‎$HOME‎ یا جای دیگر، رویکرد بهتری می‌باشد. به عنوان یک موضوع فرعی، پیشوند pid درجه‌ای از کنترل یا آگاهی بر هر دایرکتوری موقتی ایجاد شده را فعال می‌کند. شخصاً ترجیح می‌دهم این مورد را در ترکیب با فراخوان‌های trap و استفاده از ‎$TMPDIR‎ ، که برای ‎POSIX sh‎ قابل حمل است را داشته باشم تا فراخوانی mktemp که من نمی‌توانم به آن تکیه کنم. -- igli

سایر راهکارها

من تصریح می‌کنم که بهترین راه‌حل برای نگهداری فایلهای اختصاصی شما استفاده از دایرکتوری ‎$HOME‎ شما می‌باشد. اگر شما در حال پیاده‌سازی یک سرویس کمکی یا موردی هستید که تحت یک حساب کاربری اجرا می‌شود، چرا به سادگی یک دایرکتوری اختصاصی برای آن سرویس در همان زمانی که آن کد را نصب می‌کنید، نسازید؟


یک پیشنهاد نه کاملاً جدی دیگر پیوست کردن کُد C در اسکریپتی است که فرمان ‎mktemp(1)‎ را برمبنای تابع کتابخانه‌ای‎ mktemp(3)‎ پیاده‌سازی میکند. اما این کار دو مشکل دارد:

  • بلااستفاده در سیستم‌های سولاریس، جایی که به این نیاز خواهیم داشت احتمالاً کامپایلر C را نداریم.
  • مسئله مرغ و تخم مرغ: ما برای نگهداری خروجی کامپایلر به نام فایل موقتی نیاز داریم.


پرسش و پاسخ 62 (آخرین ویرایش ‎2013-01-11 04:00:34 توسط 82)


  1. مترجم: عبارتی که در ابتدا درمستندات یونیکس برای ساعت وتاریخ صفر سیستم عامل به کار رفته است، و در اکثر نگارشهای یونیکس برابر نیمه شب اول ژانویه 1970 به وقت ‎UTC (برگرفته از Universal Time Coordinated‎ روش مدرن و دقیقتر از وقت گرینویچ برای محاسبه یکنواخت زمان در تمام نقاط جهان است و ساعت اتمی بین‌المللی نیز گفته می‌شود)‎ می‌باشد. ساعت سیستم که در نشانه‌های زمان فایلها ثبت می‌شود(تاریخ دستیابی، ویرایش یا ایجاد) بر اساس ثانیه‌های سپری شده از epoch است. در لغت، مبداء زمان نیز گفته می‌شود. (بازگشت)


لیست تغییرات Bash در هر نگارش

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

آیا لیستی از ویژگی‌های اضافه شده به یک نگارش معین Bash وجود دارد؟

در اینجا پیوندهایی به مستندات رسمی Bash آمده است:

  • NEWS: فایل لیست موجز تغییرات بین نگارش جاری و نگارش قبلی

  • CHANGES: تاریخچه کامل تغییرات bash (فقط از نگارش2.0 به بعد)

  • COMPAT: مسائل سازگاری بین bash3 و نگارش‌های قبلی

لیست خلاصه گسترده‌تر از لیست پایین می‌تواند دراینجا یافت شود تغییرات Bash

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

ویژگی

اضافه شده در نگارش

\uXXXX and \UXXXXXXXX

4.2-alpha

declare -g

4.2-alpha

test -v

4.2-alpha

printf %(fmt)T

4.2-alpha

array[-idx] and ${var:start:-len}

4.2-alpha

lastpipe (shopt)

4.2-alpha

read -N

4.1-alpha

{var}> or {var}< etc. (FD variable assignment)

4.1-alpha

syslog history (compile option)

4.1-alpha

BASH_XTRACEFD

4.1-alpha

;& and ;;& fall-throughs for case

4.0-alpha

associative arrays

4.0-alpha

&>> and |&

4.0-alpha

command_not_found_handle

4.0-alpha

coproc

4.0-alpha

globstar

4.0-alpha

mapfile/readarray

4.0-alpha

${var,[,]} and ${var^[^]}

4.0-alpha

{009..012} (leading zeros in brace expansions)

4.0-alpha

{x..y..incr}

4.0-alpha

read -t 0

4.0-alpha

read -i

4.0-alpha

x+=string array+=(string)

3.1-alpha1

printf -v var

3.1-alpha1

{x..y}

3.0-alpha

${!array[@]}

3.0-alpha

[[ =~

3.0-alpha

<<<

2.05b-alpha1

i++

2.04-devel

for ((;;))

2.04-devel

/dev/fd/N, /dev/tcp/host/port, etc.

2.04-devel

a=(*.txt) file expansion

2.03-alpha

extglob

2.02-alpha1

[[

2.02-alpha1

builtin printf

2.02-alpha1

$(< filename)

2.02-alpha1

** (exponentiation)

2.02-alpha1

\xNNN

2.02-alpha1

(( ))

2.0-beta2


پرسش و پاسخ شماره 61 (آخرین ویرایش ‎ 2012-05-07 12:12:43 ‎ توسط geirha)


تعویض دایرکتوری با اسکریپت!


من سعی می‌کنم اسکریپتی بنویسم که دایرکتوری جاری را تغییر دهد( یا یک متغیر را تنظیم کند)، اما بعد از به پایان رسیدن اسکریپت، در همان جایی هستم که از آنجا شروع کرده بودم(یا متغیر من نیست)!

این را ملاحظه نمایید:

   #!/bin/sh
   cd /tmp

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

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

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

   echo 'cd /tmp' > "$HOME/mycd"      #‎ ایجاد می‌کند‎ 'cd /tmp' فایلی محتوی فرمان 
   . $HOME/mycd          # در شل جاری 'cd /tmp' آن فایل منبع می‌شود، اجرای فرمان
   pwd                   #  هستیم /tmpاکنون ما در شاخه 

همین مورد در تنظیم متغیرها اِعمال می‌گردد. . ("dot in") فایلی که شامل دستورات است، سعی نمی‌کند آن فایل را اجرا کند.

اگر دستوری که اجرا می‌کنید یک تابع است، نه یک اسکریپت، در پوسته جاری اجرا خواهد شد. بنابراین، ممکن است برای انجام آنچه در مثال فوق سعی کردیم با فایل خارجی انجام بدهیم، بدون احتیاج به هر گونه "dot in" یا "source" یک تابع تعریف شود. تعریف تابع زیر و سپس فراخوانی ساده آن با تایپ mycd:

   mycd() { cd /tmp; }

اگر می‌خواهید به طور خودکار در پوسته جدیدی که باز می‌کنید تابع در دسترس باشد، آن را در ‎ ~/.bashrc یا مشابه آن قرار بدهید.

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

   alias mycd='cd /tmp'  # .معادل تابع نشان داده شده در بالا

   alias cdlstmp='cd /tmp && ls tmp*'
   # شروع می‌شوند "tmp" می‌برد و نشان می‌دهد آنجا کدام فایلها با /tmp شما را به  

   cdls() { cd "$1" && ls; }
   # توسط مستعارها نمی‌تواند انجام شود‎
   #  cdls directory نحوه استفاده

پرسش و پاسخ 60 (آخرین ویرایش ‎ 2012-01-27 22:50:33 ‎ توسط 125)


RaceCondition


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

برای مثال، دو برنامه را در نظر بگیرید که در یک زمان اجرا می‌شوند:

  #!/bin/sh
  # برنامه اول‎
  read number < file
  number=$(($number + 1))
  echo $number > file

  #!/bin/sh
  # برنامه دوم‎
  read number < file
  number=$(($number - 1))
  echo $number > file

برنامه اول، یک عدد را از فایل می‌خواند، در حافظه یکی به آن اضافه می‌کند، و آنوقت جواب را در فایل می‌نویسد. برنامه دوم عدد را می‌خواند، یک را از آن کم می‌کند، و سپس پاسخ را در فایل می‌نویسد. فرض کنید ما عدد 42 را در فایل بگذاریم و هر دو برنامه را در یک زمان اجرا کنیم. چه اتفاقی رخ می‌دهد؟

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

خوب، به طور حتم این یک پیامد محتمل می‌باشد. اما تنها نتیجه ممکن نیست، به علت اینکه برنامه‌ها atomic نیستند -- یعنی، آنها تمام مراحل خود را بدون انقطاع انجام نمی‌دهند.

یک توالی احتمالی دیگر وقوع رویدادها چنین است:

  1. برنامه اول عدد 42 را از فایل می‌خواند.
  2. برنامه دوم عدد 42 را از فایل می‌خواند.
  3. برنامه اول 1 را به عددش اضافه می‌کند، و اکنون در حافظه 43 را دارد.
  4. برنامه دوم 1 را از عددش کم می‌کند، و حالا 41 را در حافظه دارد.
  5. برنامه اول 43 را در فایل می‌نویسد.
  6. برنامه دوم 41 را در فایل می‌نویسد. نتیجه نهایی: 41

اگر دو سطر انتهایی به طور برعکس رخ بدهند، آنوقت جواب نهایی 43 خواهد شد. بنابراین، به نسبت تمایل زمان بندی سیستم‌عامل، می‌توانیم نتایج انتهایی 41, 42 یا ‏43 را داشته باشیم.

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

  • RaceCondition (آخرین ویرایش ‎2009-02-04 20:56:56‎ توسط GreyCat)

fork بمب


من این دستور را در جایی دیدم: ‎:(){ :|:& }‎ (بمب خوشه‌ای). این چطور کار می‌کند؟

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

بمب خوشه‌ای یک شکل ساده تکذیب سرویس(یا حمله DoS) است که بر مبنای نام فراخوان سیستم یونیکسیِ ‎fork(2)‎ نام گذاری گردیده است. برنامه‌ای است که توسط انشعاب کپی‌های خودش به طور مکرر، که فرزندان نیز به طور بازگشتی همان کار را می‌کنند، به سرعت منابع سیستم را تحلیل می‌برد. در بسیاری از سیستم‌هایِ بدون محدودیت صحیحِ منابع، این مورد ممکن است شما را در یک وضعیت اصلاح ناپذیر غیرپاسخگو رها کند.

این تعریف ویژه از بمب fork در Bash بنا به دلایلی چنان مشهور است که گاهی اوقات بمب خوشه‌ای نامیده می‌شود.

در اینجا رایج‌ترین شکل مورد پسند عامه کد آن آمده است:

:(){ :|:& };:

و از طرف دیگر، با قواعد مناسب برای خوانایی به این صورت:

#!/usr/bin/env bash
:() { 
    : | : &
}

:

این کد تابعی به نام : تعریف می‌کند. بدنه تابع یک لوله را تنظیم می‌کند، که در Bash متشکل از دو پوسته فرعی می‌باشد، خروجی استاندارد اولی توسط یک لوله به ورودی استاندارد دومی متصل گردیده است. تابع (پوسته والد لوله) لوله را پس‌زمینه‌ای می‌سازد، تابع باز می‌گردد و پوسته با رها نمودن job در پس زمینه، خاتمه می‌یابد. نتیجه نهایی دو پردازش جدید است که هر کدام پردازش : را برای تکرار فرآیند، فراخوانی می‌کنند.

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

bomb() {
    bomb | bomb &
}

bomb

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

در نتیجه، تنها راه محافظت از خودتان در برابر چنین سوءاستفاده‌ای، محدودیتِ حداکثرِ مجازِ استفاده از منابع برای کاربرانتان می‌باشد. چنین منابعی به وسیله فراخوان سیستمی ‎setrlimit(2)‎ مقرر می‌شود. واسط این قابلیت در Bash و پوسته Korn فرمان ‎ulimit‎ است. همچنین ممکن است سیستم عامل شما فایلهای پیکربندی ویژه‌ای برای کمک به مدیریت این منابع داشته باشد( برای مثال، فایل ‎/etc/security/limits.conf‎ در دبیان، یا ‎/etc/login.conf‎ در OpenBSD). برای جزئیات، مستندات سیستم خود را کنکاش نمایید.

چرا ‎'':(){ :|:& };:''‎ روش نامساعدی برای تعریف یک بمب خوشه‌ای است

این تعریف عامه پسند به علت یک ترکیب غیرعادی جزئیات (در پوسته‌هایی که من با آنها تست کرده‌ام) که فقط در Bash غیر POSIX و Zsh(تمام حالت‌های شبیه‌سازی) پیش می‌آید، کار می‌کند.

  1. پوسته باید تعریف نامهای تابع، ماورای آنها که به واسطه یک ‎POSIX "Name"‎ مجاز هستند را اجازه بدهد. این مطلب بلافاصله ksh93 و Bash در وضعیت POSIX و Dash و Posh ( Posh یک شاخه قدیمی pdksh است که دیگر پشتیبانی نمی‌شود)، و ‎Busybox sh‎ را رد می‌کند.

  2. یا باید پوسته:
    • به طور نادرست توابعی مقرر کند که داخلی‌های ویژه را پیش از داخلی خودش بارگذاری می‌کند. جستجو و اجرای فرمان را ببینید. mksh در این مرحله(به طور صحیح) ناموفق می‌شود، واقعاً دستور : داخلی را اجرا می‌کند. حتی اگر شما تابع را به طور موفقیت آمیز تعریف کنید، فراخوانی تابع غیر ممکن است. Bash در وضعیت غیرPOSIX و Zsh (حتی شبیه‌ساز POSIX)مطابق این ضوابط هستند.

    • یا فراهم نمودن وسیله غیر فعال‌سازی فرمان داخلی. Bash و Ksh93 انجام می‌دهند. که Bash ناموفق است (درست مطابق مستنداتش). Ksh93 موفق می‌شود( به طور نادرست بر اساس مستنداتش).
          $ bash -c 'enable -d :; type -p :'
          bash: line 0: enable: :: not dynamically loaded
          $ ksh -c 'builtin -d :; whence -v :'
          ksh: whence: :: not found
      احتمالاً یک باگ:
        -d    **.هر داخلی تعریف شده را حذف می‌کند. **داخلی ویژه نمی‌تواند حذف بشود‎
      در هر صورت، نامربوط است زیرا ksh93 قبلاً در مرحله اول ناموفق شده است. اکنون شما فقط یک داخلی غیرقابل دسترس دارید.

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

 :(){ :|:& };: 
  • -- حتماً، گمان ‌کنم می‌توانید آن را تایپ کنید.

پرسش و پاسخ 59 (آخرین ویرایش ‎2013-01-08 18:58:36‎ توسط GreyCat)